Merge branch 'master' of https://code.google.com/p/clementine-player
This commit is contained in:
commit
0b795841d5
|
@ -157,6 +157,7 @@
|
||||||
<file>icons/48x48/help-hint.png</file>
|
<file>icons/48x48/help-hint.png</file>
|
||||||
<file>icons/48x48/list-add.png</file>
|
<file>icons/48x48/list-add.png</file>
|
||||||
<file>icons/48x48/list-remove.png</file>
|
<file>icons/48x48/list-remove.png</file>
|
||||||
|
<file>icons/48x48/media-optical.png</file>
|
||||||
<file>icons/48x48/media-playback-pause.png</file>
|
<file>icons/48x48/media-playback-pause.png</file>
|
||||||
<file>icons/48x48/media-playback-start.png</file>
|
<file>icons/48x48/media-playback-start.png</file>
|
||||||
<file>icons/48x48/media-playback-stop.png</file>
|
<file>icons/48x48/media-playback-stop.png</file>
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 4.7 KiB |
|
@ -77,6 +77,9 @@ GSTREAMER_PLUGINS=[
|
||||||
|
|
||||||
# Fingerprinting support
|
# Fingerprinting support
|
||||||
'libgstofa.so',
|
'libgstofa.so',
|
||||||
|
|
||||||
|
# CD support
|
||||||
|
'libgstcdio.so',
|
||||||
]
|
]
|
||||||
|
|
||||||
GSTREAMER_SEARCH_PATH=[
|
GSTREAMER_SEARCH_PATH=[
|
||||||
|
|
|
@ -193,6 +193,7 @@ set(SOURCES
|
||||||
playlistparsers/xspfparser.cpp
|
playlistparsers/xspfparser.cpp
|
||||||
|
|
||||||
resolvers/libraryresolver.cpp
|
resolvers/libraryresolver.cpp
|
||||||
|
resolvers/songresolver.cpp
|
||||||
|
|
||||||
smartplaylists/generator.cpp
|
smartplaylists/generator.cpp
|
||||||
smartplaylists/generatorinserter.cpp
|
smartplaylists/generatorinserter.cpp
|
||||||
|
@ -406,6 +407,7 @@ set(HEADERS
|
||||||
|
|
||||||
resolvers/libraryresolver.h
|
resolvers/libraryresolver.h
|
||||||
resolvers/resolver.h
|
resolvers/resolver.h
|
||||||
|
resolvers/songresolver.h
|
||||||
|
|
||||||
smartplaylists/generator.h
|
smartplaylists/generator.h
|
||||||
smartplaylists/generatorinserter.h
|
smartplaylists/generatorinserter.h
|
||||||
|
|
|
@ -121,7 +121,7 @@ void CddaDevice::Init() {
|
||||||
musicbrainz_client->StartDiscIdRequest(musicbrainz_discid);
|
musicbrainz_client->StartDiscIdRequest(musicbrainz_discid);
|
||||||
g_free(string_mb);
|
g_free(string_mb);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean all the Gstreamer objects we have used: we don't need them anymore
|
// Clean all the Gstreamer objects we have used: we don't need them anymore
|
||||||
gst_element_set_state (pipe, GST_STATE_NULL);
|
gst_element_set_state (pipe, GST_STATE_NULL);
|
||||||
gst_object_unref(GST_OBJECT(pipe));
|
gst_object_unref(GST_OBJECT(pipe));
|
||||||
|
@ -156,8 +156,8 @@ void CddaDevice::AudioCDTagsLoaded(const QString& artist, const QString& album,
|
||||||
}
|
}
|
||||||
|
|
||||||
void CddaDevice::Refresh() {
|
void CddaDevice::Refresh() {
|
||||||
if ((cdio_ && cdda_) && /* already init... */
|
if ((cdio_ && cdda_) && /* already init... */
|
||||||
!cdio_get_media_changed(cdio_) /* ...and hasn't change since last time */) {
|
cdio_get_media_changed(cdio_) != 1 /* ...and hasn't change since last time */) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Check if mutex is already token (i.e. init is already taking place)
|
// Check if mutex is already token (i.e. init is already taking place)
|
||||||
|
|
|
@ -92,14 +92,29 @@ void CddaLister::UpdateDeviceFreeSpace(const QString&) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CddaLister::Init() {
|
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);
|
char **devices = cdio_get_devices(DRIVER_DEVICE);
|
||||||
if (!devices) {
|
if (!devices) {
|
||||||
|
qLog(Debug) << "No CD devices found";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (; *devices != NULL; ++devices) {
|
for (; *devices != NULL; ++devices) {
|
||||||
if (strcmp("/dev/cdrom", *devices) == 0)
|
if (strcmp("/dev/cdrom", *devices) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
QString device(*devices);
|
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;
|
devices_list_ << device;
|
||||||
emit DeviceAdded(device);
|
emit DeviceAdded(device);
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ void MusicBrainzClient::DiscIdRequestFinished() {
|
||||||
ResultList ret;
|
ResultList ret;
|
||||||
QString artist;
|
QString artist;
|
||||||
QString album;
|
QString album;
|
||||||
|
|
||||||
if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != 200) {
|
if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != 200) {
|
||||||
emit Finished(artist, album, ret);
|
emit Finished(artist, album, ret);
|
||||||
return;
|
return;
|
||||||
|
@ -117,11 +117,14 @@ void MusicBrainzClient::DiscIdRequestFinished() {
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!reader.atEnd()) {
|
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);
|
Result track = ParseTrack(&reader);
|
||||||
if (!track.title_.isEmpty()) {
|
if (!track.title_.isEmpty()) {
|
||||||
ret << track;
|
ret << track;
|
||||||
}
|
}
|
||||||
|
} else if (token == QXmlStreamReader::EndElement && reader.name() == "track-list") {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "library/librarybackend.h"
|
#include "library/librarybackend.h"
|
||||||
#include "library/libraryquery.h"
|
#include "library/libraryquery.h"
|
||||||
#include "library/sqlrow.h"
|
#include "library/sqlrow.h"
|
||||||
|
#include "resolvers/songresolver.h"
|
||||||
|
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
|
@ -31,6 +32,9 @@ ParserBase::ParserBase(LibraryBackendInterface* library, QObject *parent)
|
||||||
void ParserBase::LoadSong(const QString& filename_or_url, qint64 beginning,
|
void ParserBase::LoadSong(const QString& filename_or_url, qint64 beginning,
|
||||||
const QDir& dir, Song* song) const {
|
const QDir& dir, Song* song) const {
|
||||||
if (filename_or_url.isEmpty()) {
|
if (filename_or_url.isEmpty()) {
|
||||||
|
// Try and resolve from various sources.
|
||||||
|
SongResolver resolver(library_);
|
||||||
|
resolver.ResolveSong(song);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,13 +90,13 @@ Song XSPFParser::ParseTrack(QXmlStreamReader* reader, const QDir& dir) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
return_song:
|
return_song:
|
||||||
Song song = LoadSong(location, 0, dir);
|
Song song;
|
||||||
|
|
||||||
// Override metadata with what was in the playlist
|
|
||||||
song.set_title(title);
|
song.set_title(title);
|
||||||
song.set_artist(artist);
|
song.set_artist(artist);
|
||||||
song.set_album(album);
|
song.set_album(album);
|
||||||
song.set_length_nanosec(nanosec);
|
song.set_length_nanosec(nanosec);
|
||||||
|
LoadSong(location, 0, dir, &song);
|
||||||
|
|
||||||
return song;
|
return song;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ int LibraryResolver::ResolveSong(const Song& song) {
|
||||||
LibraryQuery* query = new LibraryQuery;
|
LibraryQuery* query = new LibraryQuery;
|
||||||
query->AddWhere("artist", song.artist());
|
query->AddWhere("artist", song.artist());
|
||||||
query->AddWhere("title", song.title());
|
query->AddWhere("title", song.title());
|
||||||
|
query->SetColumnSpec("%songs_table.ROWID, " + Song::kColumnSpec);
|
||||||
|
|
||||||
QFuture<bool> future = QtConcurrent::run(
|
QFuture<bool> future = QtConcurrent::run(
|
||||||
backend_, &LibraryBackendInterface::ExecQuery, query);
|
backend_, &LibraryBackendInterface::ExecQuery, query);
|
||||||
|
|
|
@ -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<SpotifyService>()->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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef SONGRESOLVER_H
|
||||||
|
#define SONGRESOLVER_H
|
||||||
|
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QList>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#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<Resolver*> resolvers_;
|
||||||
|
Song* song_;
|
||||||
|
|
||||||
|
QEventLoop loop_;
|
||||||
|
|
||||||
|
int resolvers_finished_;
|
||||||
|
bool resolved_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue