diff --git a/data/data.qrc b/data/data.qrc
index 11f36f9c9..06c998d76 100644
--- a/data/data.qrc
+++ b/data/data.qrc
@@ -157,6 +157,7 @@
icons/48x48/help-hint.png
icons/48x48/list-add.png
icons/48x48/list-remove.png
+ icons/48x48/media-optical.png
icons/48x48/media-playback-pause.png
icons/48x48/media-playback-start.png
icons/48x48/media-playback-stop.png
diff --git a/data/icons/48x48/media-optical.png b/data/icons/48x48/media-optical.png
new file mode 100644
index 000000000..e4cb7aab9
Binary files /dev/null and b/data/icons/48x48/media-optical.png differ
diff --git a/dist/macdeploy.py b/dist/macdeploy.py
index a90e9ae6b..73ac40c0d 100755
--- a/dist/macdeploy.py
+++ b/dist/macdeploy.py
@@ -77,6 +77,9 @@ GSTREAMER_PLUGINS=[
# Fingerprinting support
'libgstofa.so',
+
+ # CD support
+ 'libgstcdio.so',
]
GSTREAMER_SEARCH_PATH=[
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d8e11d7f6..8b1e920ca 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -193,6 +193,7 @@ set(SOURCES
playlistparsers/xspfparser.cpp
resolvers/libraryresolver.cpp
+ resolvers/songresolver.cpp
smartplaylists/generator.cpp
smartplaylists/generatorinserter.cpp
@@ -406,6 +407,7 @@ set(HEADERS
resolvers/libraryresolver.h
resolvers/resolver.h
+ resolvers/songresolver.h
smartplaylists/generator.h
smartplaylists/generatorinserter.h
diff --git a/src/devices/cddadevice.cpp b/src/devices/cddadevice.cpp
index 736647494..cddfdec26 100644
--- a/src/devices/cddadevice.cpp
+++ b/src/devices/cddadevice.cpp
@@ -121,7 +121,7 @@ void CddaDevice::Init() {
musicbrainz_client->StartDiscIdRequest(musicbrainz_discid);
g_free(string_mb);
}
-
+
// Clean all the Gstreamer objects we have used: we don't need them anymore
gst_element_set_state (pipe, GST_STATE_NULL);
gst_object_unref(GST_OBJECT(pipe));
@@ -156,8 +156,8 @@ void CddaDevice::AudioCDTagsLoaded(const QString& artist, const QString& album,
}
void CddaDevice::Refresh() {
- if ((cdio_ && cdda_) && /* already init... */
- !cdio_get_media_changed(cdio_) /* ...and hasn't change since last time */) {
+ if ((cdio_ && cdda_) && /* already init... */
+ cdio_get_media_changed(cdio_) != 1 /* ...and hasn't change since last time */) {
return;
}
// Check if mutex is already token (i.e. init is already taking place)
diff --git a/src/devices/cddalister.cpp b/src/devices/cddalister.cpp
index 53e485cd1..179dcc303 100644
--- a/src/devices/cddalister.cpp
+++ b/src/devices/cddalister.cpp
@@ -92,14 +92,29 @@ void CddaLister::UpdateDeviceFreeSpace(const QString&) {
}
void CddaLister::Init() {
+ cdio_init();
+#ifdef Q_OS_DARWIN
+ if (!cdio_have_driver(DRIVER_OSX)) {
+ qLog(Error) << "libcdio was compiled without support for OS X!";
+ }
+#endif
char **devices = cdio_get_devices(DRIVER_DEVICE);
if (!devices) {
+ qLog(Debug) << "No CD devices found";
return;
}
for (; *devices != NULL; ++devices) {
if (strcmp("/dev/cdrom", *devices) == 0)
continue;
+
QString device(*devices);
+#ifdef Q_OS_DARWIN
+ // Every track is detected as a separate device on Darwin. The raw disk looks
+ // like /dev/rdisk1
+ if (!device.contains(QRegExp("^/dev/rdisk[0-9]$"))) {
+ continue;
+ }
+#endif
devices_list_ << device;
emit DeviceAdded(device);
}
diff --git a/src/musicbrainz/musicbrainzclient.cpp b/src/musicbrainz/musicbrainzclient.cpp
index 2d1401d2e..d8a847b67 100644
--- a/src/musicbrainz/musicbrainzclient.cpp
+++ b/src/musicbrainz/musicbrainzclient.cpp
@@ -91,7 +91,7 @@ void MusicBrainzClient::DiscIdRequestFinished() {
ResultList ret;
QString artist;
QString album;
-
+
if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != 200) {
emit Finished(artist, album, ret);
return;
@@ -117,11 +117,14 @@ void MusicBrainzClient::DiscIdRequestFinished() {
}
while (!reader.atEnd()) {
- if (reader.readNext() == QXmlStreamReader::StartElement && reader.name() == "track") {
+ QXmlStreamReader::TokenType token = reader.readNext();
+ if (token == QXmlStreamReader::StartElement && reader.name() == "track") {
Result track = ParseTrack(&reader);
if (!track.title_.isEmpty()) {
ret << track;
}
+ } else if (token == QXmlStreamReader::EndElement && reader.name() == "track-list") {
+ break;
}
}
diff --git a/src/playlistparsers/parserbase.cpp b/src/playlistparsers/parserbase.cpp
index 613e6be57..49c9b20e5 100644
--- a/src/playlistparsers/parserbase.cpp
+++ b/src/playlistparsers/parserbase.cpp
@@ -19,6 +19,7 @@
#include "library/librarybackend.h"
#include "library/libraryquery.h"
#include "library/sqlrow.h"
+#include "resolvers/songresolver.h"
#include
@@ -31,6 +32,9 @@ ParserBase::ParserBase(LibraryBackendInterface* library, QObject *parent)
void ParserBase::LoadSong(const QString& filename_or_url, qint64 beginning,
const QDir& dir, Song* song) const {
if (filename_or_url.isEmpty()) {
+ // Try and resolve from various sources.
+ SongResolver resolver(library_);
+ resolver.ResolveSong(song);
return;
}
diff --git a/src/playlistparsers/xspfparser.cpp b/src/playlistparsers/xspfparser.cpp
index 468fff829..660be3e3e 100644
--- a/src/playlistparsers/xspfparser.cpp
+++ b/src/playlistparsers/xspfparser.cpp
@@ -90,13 +90,13 @@ Song XSPFParser::ParseTrack(QXmlStreamReader* reader, const QDir& dir) const {
}
return_song:
- Song song = LoadSong(location, 0, dir);
-
- // Override metadata with what was in the playlist
+ Song song;
song.set_title(title);
song.set_artist(artist);
song.set_album(album);
song.set_length_nanosec(nanosec);
+ LoadSong(location, 0, dir, &song);
+
return song;
}
diff --git a/src/resolvers/libraryresolver.cpp b/src/resolvers/libraryresolver.cpp
index fa8d2bedb..6269fb590 100644
--- a/src/resolvers/libraryresolver.cpp
+++ b/src/resolvers/libraryresolver.cpp
@@ -22,6 +22,7 @@ int LibraryResolver::ResolveSong(const Song& song) {
LibraryQuery* query = new LibraryQuery;
query->AddWhere("artist", song.artist());
query->AddWhere("title", song.title());
+ query->SetColumnSpec("%songs_table.ROWID, " + Song::kColumnSpec);
QFuture future = QtConcurrent::run(
backend_, &LibraryBackendInterface::ExecQuery, query);
diff --git a/src/resolvers/songresolver.cpp b/src/resolvers/songresolver.cpp
new file mode 100644
index 000000000..2b68bd3a1
--- /dev/null
+++ b/src/resolvers/songresolver.cpp
@@ -0,0 +1,51 @@
+#include "songresolver.h"
+
+#include "core/logging.h"
+#include "core/song.h"
+#include "internet/internetmodel.h"
+#include "internet/spotifyservice.h"
+#include "libraryresolver.h"
+#include "spotifyresolver.h"
+
+SongResolver::SongResolver(LibraryBackendInterface* library, QObject* parent)
+ : QObject(parent),
+ song_(NULL),
+ resolvers_finished_(0),
+ resolved_(false) {
+ // Register in the order they should be checked.
+ RegisterResolver(new LibraryResolver(library));
+ RegisterResolver(new SpotifyResolver(InternetModel::Service()->server()));
+}
+
+SongResolver::~SongResolver() {
+ qDeleteAll(resolvers_);
+ resolvers_.clear();
+}
+
+void SongResolver::RegisterResolver(Resolver* resolver) {
+ resolvers_ << resolver;
+ connect(resolver, SIGNAL(ResolveFinished(int, SongList)), SLOT(ResolveFinished(int, SongList)));
+}
+
+bool SongResolver::ResolveSong(Song* song) {
+ song_ = song;
+ foreach (Resolver* resolver, resolvers_) {
+ resolver->ResolveSong(*song);
+ }
+ loop_.exec();
+ return resolved_;
+}
+
+void SongResolver::ResolveFinished(int, SongList resolved_songs) {
+ ++resolvers_finished_;
+ if (resolvers_finished_ == resolvers_.size()) {
+ loop_.quit();
+ }
+
+ if (!resolved_songs.isEmpty()) {
+ *song_ = resolved_songs.first();
+ qLog(Debug) << "Resolved song:" << song_->title() << "from:" << sender()->metaObject()->className();
+ resolved_ = true;
+ loop_.quit();
+ }
+}
diff --git a/src/resolvers/songresolver.h b/src/resolvers/songresolver.h
new file mode 100644
index 000000000..dbecf4185
--- /dev/null
+++ b/src/resolvers/songresolver.h
@@ -0,0 +1,37 @@
+#ifndef SONGRESOLVER_H
+#define SONGRESOLVER_H
+
+#include
+#include
+#include
+
+#include "core/song.h"
+
+class LibraryBackendInterface;
+class Resolver;
+
+class SongResolver : public QObject {
+ Q_OBJECT
+ public:
+ SongResolver(LibraryBackendInterface* library, QObject* parent = 0);
+ virtual ~SongResolver();
+
+ // Blocking
+ bool ResolveSong(Song* song);
+
+ private slots:
+ void ResolveFinished(int, SongList resolved_songs);
+
+ private:
+ void RegisterResolver(Resolver* resolver);
+
+ QList resolvers_;
+ Song* song_;
+
+ QEventLoop loop_;
+
+ int resolvers_finished_;
+ bool resolved_;
+};
+
+#endif