Combining the following upstream commits to migrate to musibrainz5: 536b679d8a0e4d3c470366b5bdfe142edb1c9307 908815f9fc7a0d7ebeae68c14a02026464b6c935 86128bdfef49d241e6aa71f968c614b8b07462de c3c68d6015f967b07bf6fd66f8fcb5d65b9122e4 diff --git a/CMakeLists.txt b/CMakeLists.txt index f1a9462..32c7656 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,13 +8,15 @@ include(KDE4Defaults) include(MacroLibrary) include_directories(${QT_INCLUDES} ${KDE4_INCLUDES}) -find_package(MusicBrainz3 REQUIRED) +find_package(MusicBrainz5 REQUIRED) +find_package(DiscId REQUIRED) include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/gui ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} - ${MUSICBRAINZ3_INCLUDE_DIR} + ${MUSICBRAINZ5_INCLUDE_DIR} + ${DISCID_INCLUDE_DIR} ) add_subdirectory(tests) ########### next target ############### @@ -112,7 +114,8 @@ target_link_libraries(kscd ${KDE4_KIO_LIBS} ${KDE4_SOLID_LIBS} ${KDE4_PHONON_LIBS} - ${MUSICBRAINZ3_LIBRARIES} + ${MUSICBRAINZ5_LIBRARIES} + ${DISCID_LIBRARIES} ) ########### install files ############### diff --git a/cmake/FindDiscId.cmake b/cmake/FindDiscId.cmake new file mode 100644 index 0000000..6de59f5 --- /dev/null +++ b/cmake/FindDiscId.cmake @@ -0,0 +1,20 @@ +# Module to find the discid library +# It can be found at http://musicbrainz.org/doc/libdiscid +# +# It defines +# DISCID_INCLUDE_DIR - the include dir +# DISCID_LIBRARIES - the required libraries +# DISCID_FOUND - true if both of the above have been found + +# Copyright (c) 2006,2007 Laurent Montel, +# Copyright (c) 2010 Gerd Fleischer +# +# Redistribution and use is allowed according to the terms of the BSD license. + +FIND_PATH(DISCID_INCLUDE_DIR discid/discid.h) + +FIND_LIBRARY(DISCID_LIBRARIES NAMES discid) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( DiscId DEFAULT_MSG + DISCID_INCLUDE_DIR DISCID_LIBRARIES) diff --git a/cmake/FindMusicBrainz3.cmake b/cmake/FindMusicBrainz3.cmake deleted file mode 100644 index 2d11e36..0000000 --- a/cmake/FindMusicBrainz3.cmake +++ /dev/null @@ -1,40 +0,0 @@ -# Module to find the musicbrainz-3 library -# -# It defines -# MUSICBRAINZ3_INCLUDE_DIR - the include dir -# MUSICBRAINZ3_LIBRARIES - the required libraries -# MUSICBRAINZ3_FOUND - true if both of the above have been found - -# Copyright (c) 2006,2007 Laurent Montel, -# -# Redistribution and use is allowed according to the terms of the BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. - -if(MUSICBRAINZ3_INCLUDE_DIR AND MUSICBRAINZ3_LIBRARIES) - set(MUSICBRAINZ3_FIND_QUIETLY TRUE) -endif(MUSICBRAINZ3_INCLUDE_DIR AND MUSICBRAINZ3_LIBRARIES) - -# use pkg-config to get the directories and then use these values -# in the FIND_PATH() and FIND_LIBRARY() calls -find_package(PkgConfig) -pkg_check_modules(PC_LIBMUSICBRAINZ3 QUIET libmusicbrainz3) - -FIND_PATH(MUSICBRAINZ3_INCLUDE_DIR musicbrainz3/musicbrainz.h - HINTS - ${PC_LIBMUSICBRAINZ3_INCLUDEDIR} - ${PC_LIBMUSICBRAINZ3_INCLUDE_DIRS} -) - -FIND_LIBRARY( MUSICBRAINZ3_LIBRARIES NAMES musicbrainz3 - HINTS - ${PC_LIBMUSICBRAINZ3_LIBDIR} - ${PC_LIBMUSICBRAINZ3_LIB_DIRS} -) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args( MusicBrainz3 DEFAULT_MSG - MUSICBRAINZ3_INCLUDE_DIR MUSICBRAINZ3_LIBRARIES) - -MARK_AS_ADVANCED(MUSICBRAINZ3_INCLUDE_DIR MUSICBRAINZ3_LIBRARIES) - - diff --git a/cmake/FindMusicBrainz5.cmake b/cmake/FindMusicBrainz5.cmake new file mode 100644 index 0000000..0f78342 --- /dev/null +++ b/cmake/FindMusicBrainz5.cmake @@ -0,0 +1,33 @@ +# Module to find the musicbrainz-5 library +# +# It defines +# MUSICBRAINZ5_INCLUDE_DIR - the include dir +# MUSICBRAINZ5_LIBRARIES - the required libraries +# MUSICBRAINZ5_FOUND - true if both of the above have been found + +# Copyright (c) 2006,2007 Laurent Montel, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +if(MUSICBRAINZ5_INCLUDE_DIR AND MUSICBRAINZ5_LIBRARIES) + set(MUSICBRAINZ5_FIND_QUIETLY TRUE) +endif() + +find_path(MUSICBRAINZ5_INCLUDE_DIR musicbrainz5/Disc.h) + +find_library(MUSICBRAINZ5_LIBRARIES NAMES musicbrainz5cc) +if (NOT MUSICBRAINZ5_LIBRARIES) + find_library(MUSICBRAINZ5_LIBRARIES NAMES musicbrainz5) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(MusicBrainz5 DEFAULT_MSG MUSICBRAINZ5_INCLUDE_DIR MUSICBRAINZ5_LIBRARIES) + +add_library(musicbrainz SHARED IMPORTED) +set_target_properties(musicbrainz PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${MUSICBRAINZ5_INCLUDE_DIR}" + IMPORTED_LOCATION "${MUSICBRAINZ5_LIBRARIES}" +) + +mark_as_advanced(MUSICBRAINZ5_INCLUDE_DIR MUSICBRAINZ5_LIBRARIES) diff --git a/kscd.cpp b/kscd.cpp index 3bcb8f6..2c6d1a4 100644 --- a/kscd.cpp +++ b/kscd.cpp @@ -114,7 +114,7 @@ void KSCD::setupActions() m_uploadAction = m_actions->addAction( QLatin1String( "Upload Info" )); m_uploadAction->setText(i18n("Upload Info")); addAction(m_uploadAction); - connect(m_uploadAction, SIGNAL(triggered()), m_MBManager, SLOT(discUpload())); + connect(m_uploadAction, SIGNAL(triggered()), this, SLOT(discUpload())); //play/pause m_playPauseAction = m_actions->addAction( QLatin1String( "Play/Pause" )); @@ -248,6 +248,11 @@ void KSCD::discLookup() m_MBManager->discLookup(devices->getMedia()->currentSource().deviceName()); } +void KSCD::discUpload() +{ + m_MBManager->discUpload(devices->getMedia()->currentSource().deviceName()); +} + void KSCD::discLookupFinished() { // If the track dialog is open, refresh it diff --git a/kscd.h b/kscd.h index 43fd653..83f8287 100644 --- a/kscd.h +++ b/kscd.h @@ -130,6 +130,7 @@ public slots: void configureKeys(); void discLookup(); + void discUpload(); void discLookupFinished(); private: diff --git a/mbmanager.cpp b/mbmanager.cpp index 4df3803..f3fd67f 100644 --- a/mbmanager.cpp +++ b/mbmanager.cpp @@ -34,86 +34,239 @@ #include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include MBManager::MBManager():m_validInfo(true) { - + m_discid = discid_new(); } MBManager::~MBManager() { + discid_free(m_discid); +} + +static QString getTitle(MusicBrainz5::CRelease *release, MusicBrainz5::CMedium *medium) +{ + QString title; + if (!release) + { + return title; + } + + title = QString::fromUtf8(release->Title().c_str()); + if (medium && release->MediumList()->NumItems() > 1) + { + title = i18n("%1 (disc %2)", title, medium->Position()); + } + return title; } -void MBManager::discLookup(const QString &device) +static QString getArtistFromArtistCredit(MusicBrainz5::CArtistCredit *artistCredit) { - m_validInfo = true; + QString artist; + MusicBrainz5::CNameCreditList *artistList = artistCredit->NameCreditList(); + + if (!artistList) + { + return artist; + } - MusicBrainz::WebService* ws = new MusicBrainz::WebService(); + for (int i = 0; i < artistList->NumItems(); i++) + { + MusicBrainz5::CNameCredit* name = artistList->Item(i); + MusicBrainz5::CArtist* itemArtist = name->Artist(); + + if (!name->Name().empty()) + { + artist += QString::fromUtf8(name->Name().c_str()); + } + else + { + artist += QString::fromUtf8(itemArtist->Name().c_str()); + } + + artist += QString::fromUtf8(name->JoinPhrase().c_str()); + } + + return artist; +} - // Set the proper server to use. Defaults to mm.musicbrainz.org:80 - if (!qgetenv("MB_SERVER").isNull()) +static QString getArtist(MusicBrainz5::CRelease *release) +{ + QString artist; + if (!release) { - std::string server(qgetenv("MB_SERVER")); - ws->setHost(server); - //kDebug() << "!! set server !!" ; + return artist; } - else + + MusicBrainz5::CArtistCredit *artistCredit = release->ArtistCredit(); + return getArtistFromArtistCredit(artistCredit); +} + +static QList unknownTracks(QString &discArtist, DiscId *m_discid) +{ + QList tracks; + MBTrackInfo track; + for (int j = 1; j < discid_get_first_track_num(m_discid); j++) + { + track.Title = i18n("Unknown title"); + track.Artist = discArtist; + // Not an audio track + track.Duration = 0; + + tracks << track; + } + for (int j = discid_get_first_track_num(m_discid); j <= discid_get_last_track_num(m_discid); j++) + { + track.Title = i18n("Unknown title"); + track.Artist = discArtist; + // time from mb library in sectors, 75 sectors = 1 second + track.Duration = discid_get_track_length(m_discid, j) * 1000 / 75; + + tracks << track; + } + + return tracks; +} + +static QList getTracks(MusicBrainz5::CMedium *medium, QString &discArtist, DiscId *m_discid) +{ + QList tracks; + if (!medium) + { + return tracks; + } + + MusicBrainz5::CTrackList *trackList = medium->TrackList(); + if (!trackList) + { + return unknownTracks(discArtist, m_discid); + } + + MBTrackInfo track; + for (int i = 0; i < trackList->NumItems(); i++) + { + MusicBrainz5::CTrack *itemTrack = trackList->Item(i); + MusicBrainz5::CRecording *recording = itemTrack->Recording(); + if (recording && !itemTrack->ArtistCredit()) + { + track.Artist = getArtistFromArtistCredit(recording->ArtistCredit()); + } + else + { + track.Artist = getArtistFromArtistCredit(itemTrack->ArtistCredit()); + } + + if(recording && itemTrack->Title().empty()) + { + track.Title = QString::fromUtf8(recording->Title().c_str()); + } + else + { + track.Title = QString::fromUtf8(itemTrack->Title().c_str()); + } + + track.Duration = itemTrack->Length(); + + tracks << track; + } + + return tracks; +} + +static MusicBrainz5::CRelease *getRelease(MusicBrainz5::CQuery &query, std::string &discId, MusicBrainz5::CMetadata &metadata, MusicBrainz5::CMetadata &fullMetadata) +{ + metadata = query.Query("discid", discId); + // Check to see how many items were returned from the server + if (!metadata.Disc() || !metadata.Disc()->ReleaseList()) + { + return 0; + } + + MusicBrainz5::CReleaseList *results = metadata.Disc()->ReleaseList(); + + // TODO if multiple entries found + if (results->NumItems() > 1) + { + kDebug() << results->NumItems() << " entries found"; + } + + MusicBrainz5::CRelease *release; + for (int i = 0; i < results->NumItems(); i++) { - //kDebug() << "no server"; + MusicBrainz5::CRelease *result = results->Item(i); + MusicBrainz5::CQuery::tParamMap params; + params["inc"] = "artists labels recordings release-groups url-rels " + "discids artist-credits"; + fullMetadata = query.Query("release", result->ID(), "", params); + + release = fullMetadata.Release(); + if (release) + { + break; + } + } + + return release; +} + +static MusicBrainz5::CMedium *getMedium(MusicBrainz5::CRelease *release, std::string &discId, MusicBrainz5::CMediumList &mediaList) +{ + if (!release) + { + return 0; } - // If you need to use a proxy, uncomment/edit the following line - // as appropriate - //ws->setProxyHost("proxy.mydomain.com"); - //ws->setProxyPort(80); + // Find the specific media in the release + mediaList = release->MediaMatchingDiscID(discId); + MusicBrainz5::CMedium* medium = 0; - try + for (int i = 0; i < mediaList.NumItems(); i++) { - MusicBrainz::Disc *disc = MusicBrainz::readDisc(qPrintable(device)); + medium = mediaList.Item(i); + if (medium) + { + break; + } + } - MusicBrainz::Query q(ws); - MusicBrainz::ReleaseResultList results; + return medium; +} +void MBManager::discLookup(const QString &device) +{ + m_validInfo = true; + MusicBrainz5::CQuery query("kscd"); + int discid_ok = discid_read_sparse(m_discid, qPrintable(device), 0); + if (discid_ok) + { + std::string discId(discid_get_id(m_discid)); try { - MusicBrainz::ReleaseFilter f = MusicBrainz::ReleaseFilter().discId(disc->getId()); - results = q.getReleases(&f); + MusicBrainz5::CMetadata metadata, fullMetadata; + MusicBrainz5::CMediumList mediaList; + MusicBrainz5::CRelease *release = getRelease(query, discId, metadata, fullMetadata); + MusicBrainz5::CMedium *medium = getMedium(release, discId, mediaList); - // Check to see how many items were returned from the server - if (!results.empty()) + if (release && medium) { - // TODO if multiple entries found - if (results.size() > 1) - { - kDebug() << results.size() << " entries found"; - } - - MusicBrainz::ReleaseResult *result = results.front(); - MusicBrainz::Release *release = q.getReleaseById(result->getRelease()->getId(), - &MusicBrainz::ReleaseIncludes().tracks().artist()); // Sets info - m_discInfo.Title = QString::fromUtf8(release->getTitle().c_str()); - m_discInfo.Artist = QString::fromUtf8(release->getArtist()->getName().c_str()); - - m_trackList.clear(); - MBTrackInfo track; - for (MusicBrainz::TrackList::iterator j = release->getTracks().begin(); - j != release->getTracks().end(); j++) - { - MusicBrainz::Track *t = *j; - MusicBrainz::Artist *artist = t->getArtist(); - if (!artist) - artist = release->getArtist(); - - track.Title = QString::fromUtf8(t->getTitle().c_str()); - track.Artist = QString::fromUtf8(artist->getName().c_str()); - track.Duration = t->getDuration(); - - m_trackList << track; - } + m_discInfo.Title = getTitle(release, medium); + m_discInfo.Artist = getArtist(release); + + m_trackList = getTracks(medium, m_discInfo.Artist, m_discid); } else { @@ -121,75 +274,57 @@ void MBManager::discLookup(const QString &device) m_validInfo = false; } - } - catch (const MusicBrainz::WebServiceError &e) - { - kDebug() << "Error: " << e.what(); + catch (MusicBrainz5::CExceptionBase& error) + { + kDebug() << "Connection Exception: '" << error.what() << "'"; + kDebug() << "LastResult: " << query.LastResult(); + kDebug() << "LastHTTPCode: " << query.LastHTTPCode(); + kDebug() << "LastErrorMessage: " << QString::fromUtf8(query.LastErrorMessage().c_str()); + m_validInfo = false; - } + } catch (...) { kDebug() << "Caught Unknown Exception:"; m_validInfo = false; } - - if (!m_validInfo) - { - // If invalid data, fill the information with something - // Sets info - m_discInfo.Title = i18n("Unknown album"); - m_discInfo.Artist = i18n("Unknown artist"); - - m_trackList.clear(); - MBTrackInfo track; - for (MusicBrainz::Disc::TrackList::iterator j = disc->getTracks().begin(); j != disc->getTracks().end(); j++) - { - track.Title = i18n("Unknown title"); - track.Artist = m_discInfo.Artist; - // time from mb library in sectors, 75 sectors = 1 second - track.Duration = (*j).second*1000/75; - - m_trackList << track; - } - } - delete disc; } - // FIXME Doesn't seem to get caught, why? - catch (const MusicBrainz::DiscError &e) - { - kDebug() << "Error: " << e.what(); - m_discInfo.Title = i18n("Unknown album"); - m_discInfo.Artist = i18n("Unknown artist"); - m_discInfo.Artist = i18n( "No Disc" ); - m_trackList.clear(); - } - catch(...) + else + { + m_validInfo = false; + } + + if (!m_validInfo) { + // If invalid data, fill the information with something + // Sets info m_discInfo.Title = i18n("Unknown album"); m_discInfo.Artist = i18n("Unknown artist"); - m_discInfo.Artist = i18n( "No Disc" ); + m_trackList.clear(); + if (discid_ok) + { + m_trackList = unknownTracks(m_discInfo.Artist, m_discid); + } } - + emit discLookupFinished(); } -void MBManager::discUpload() +void MBManager::discUpload(const QString &device) { showArtistLabel(m_discInfo.Artist); + const char *discid_device = device.isEmpty()? NULL : qPrintable(device); - try + int ok = discid_read_sparse(m_discid, discid_device, 0); + if (ok) { - MusicBrainz::Disc *disc = MusicBrainz::readDisc(); - std::string url = MusicBrainz::getSubmissionUrl(disc); - delete disc; - - KToolInvocation::invokeBrowser(QString::fromUtf8(url.c_str())); + QString url = QString::fromUtf8(discid_get_submission_url(m_discid)); + KToolInvocation::invokeBrowser(url); } - catch (MusicBrainz::DiscError &e) + else { - kDebug() << "Error: " << e.what(); + kDebug() << "Error: " << discid_get_error_msg(m_discid); } } - diff --git a/mbmanager.h b/mbmanager.h index 6b07e95..ea04153 100644 --- a/mbmanager.h +++ b/mbmanager.h @@ -42,6 +42,9 @@ #include #include +// musicbrainz discid +#include + struct DiscInfo { QString Title; @@ -64,6 +67,7 @@ private: QList m_trackList; /// List of tracks information bool m_validInfo; /// Tells whether the lookup query succeeded + DiscId *m_discid; public: MBManager(); @@ -82,11 +86,11 @@ public slots: void discLookup(const QString& device); /** Uploads information */ - void discUpload(); + void discUpload(const QString& device=QString()); signals: void showArtistLabel(QString&); - + void discLookupFinished(); };