mirror of
https://github.com/clementine-player/Clementine
synced 2024-12-16 19:31:02 +01:00
Use FSEvent-based filesystem watcher on Mac.
(cherry picked from commit 9fdfb52225
)
This commit is contained in:
parent
ea9a8ea2ed
commit
ec2f57148b
@ -66,6 +66,7 @@ set(SOURCES
|
||||
core/deletefiles.cpp
|
||||
core/encoding.cpp
|
||||
core/filesystemmusicstorage.cpp
|
||||
core/filesystemwatcherinterface.cpp
|
||||
core/fht.cpp
|
||||
core/fmpsparser.cpp
|
||||
core/globalshortcutbackend.cpp
|
||||
@ -80,6 +81,7 @@ set(SOURCES
|
||||
core/organise.cpp
|
||||
core/organiseformat.cpp
|
||||
core/player.cpp
|
||||
core/qtfslistener.cpp
|
||||
core/qxtglobalshortcutbackend.cpp
|
||||
core/scopedtransaction.cpp
|
||||
core/settingsprovider.cpp
|
||||
@ -332,6 +334,7 @@ set(HEADERS
|
||||
core/crashreporting.h
|
||||
core/database.h
|
||||
core/deletefiles.h
|
||||
core/filesystemwatcherinterface.h
|
||||
core/globalshortcuts.h
|
||||
core/globalshortcutbackend.h
|
||||
core/gnomeglobalshortcutbackend.h
|
||||
@ -340,6 +343,7 @@ set(HEADERS
|
||||
core/network.h
|
||||
core/organise.h
|
||||
core/player.h
|
||||
core/qtfslistener.h
|
||||
core/songloader.h
|
||||
core/taskmanager.h
|
||||
core/urlhandler.h
|
||||
|
23
src/core/filesystemwatcherinterface.cpp
Normal file
23
src/core/filesystemwatcherinterface.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include "filesystemwatcherinterface.h"
|
||||
|
||||
#include "qtfslistener.h"
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#include "macfslistener.h"
|
||||
#endif
|
||||
|
||||
FileSystemWatcherInterface::FileSystemWatcherInterface(QObject* parent)
|
||||
: QObject(parent) {
|
||||
}
|
||||
|
||||
FileSystemWatcherInterface* FileSystemWatcherInterface::Create(QObject* parent) {
|
||||
FileSystemWatcherInterface* ret;
|
||||
#ifdef Q_OS_DARWIN
|
||||
ret = new MacFSListener(parent);
|
||||
#else
|
||||
ret = new QtFSListener(parent);
|
||||
#endif
|
||||
|
||||
ret->Init();
|
||||
return ret;
|
||||
}
|
19
src/core/filesystemwatcherinterface.h
Normal file
19
src/core/filesystemwatcherinterface.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef FILESYSTEMWATCHERINTERFACE_H
|
||||
#define FILESYSTEMWATCHERINTERFACE_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class FileSystemWatcherInterface : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
FileSystemWatcherInterface(QObject* parent = 0);
|
||||
virtual void Init() {}
|
||||
virtual void AddPath(const QString& path) = 0;
|
||||
|
||||
static FileSystemWatcherInterface* Create(QObject* parent = 0);
|
||||
|
||||
signals:
|
||||
void PathChanged(const QString& path);
|
||||
};
|
||||
|
||||
#endif
|
@ -6,7 +6,9 @@
|
||||
#include <QObject>
|
||||
#include <QSet>
|
||||
|
||||
class MacFSListener : public QObject {
|
||||
#include "filesystemwatcherinterface.h"
|
||||
|
||||
class MacFSListener : public FileSystemWatcherInterface {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "core/scoped_nsobject.h"
|
||||
|
||||
MacFSListener::MacFSListener(QObject* parent)
|
||||
: QObject(parent),
|
||||
: FileSystemWatcherInterface(parent),
|
||||
run_loop_(NULL),
|
||||
stream_(NULL) {
|
||||
}
|
||||
@ -34,12 +34,14 @@ void MacFSListener::EventStreamCallback(
|
||||
}
|
||||
|
||||
void MacFSListener::AddPath(const QString& path) {
|
||||
Q_ASSERT(run_loop_);
|
||||
paths_.insert(path);
|
||||
UpdateStream();
|
||||
}
|
||||
|
||||
void MacFSListener::UpdateStream() {
|
||||
if (stream_) {
|
||||
FSEventStreamStop(stream_);
|
||||
FSEventStreamInvalidate(stream_);
|
||||
FSEventStreamRelease(stream_);
|
||||
stream_ = NULL;
|
||||
|
12
src/core/qtfslistener.cpp
Normal file
12
src/core/qtfslistener.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
#include "qtfslistener.h"
|
||||
|
||||
QtFSListener::QtFSListener(QObject* parent)
|
||||
: FileSystemWatcherInterface(parent),
|
||||
watcher_(this) {
|
||||
connect(&watcher_, SIGNAL(directoryChanged(const QString&)),
|
||||
SIGNAL(PathChanged(const QString&)));
|
||||
}
|
||||
|
||||
void QtFSListener::AddPath(const QString& path) {
|
||||
watcher_.addPath(path);
|
||||
}
|
19
src/core/qtfslistener.h
Normal file
19
src/core/qtfslistener.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef QTFSLISTENER_H
|
||||
#define QTFSLISTENER_H
|
||||
|
||||
#include "filesystemwatcherinterface.h"
|
||||
|
||||
#include <QFileSystemWatcher>
|
||||
|
||||
class QtFSListener : public FileSystemWatcherInterface {
|
||||
Q_OBJECT
|
||||
public:
|
||||
QtFSListener(QObject* parent);
|
||||
virtual void AddPath(const QString& path);
|
||||
|
||||
private:
|
||||
QFileSystemWatcher watcher_;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
@ -16,9 +16,11 @@
|
||||
*/
|
||||
|
||||
#include "library.h"
|
||||
|
||||
#include "librarymodel.h"
|
||||
#include "librarybackend.h"
|
||||
#include "core/database.h"
|
||||
#include "core/filesystemwatcherinterface.h"
|
||||
#include "smartplaylists/generator.h"
|
||||
#include "smartplaylists/querygenerator.h"
|
||||
#include "smartplaylists/search.h"
|
||||
@ -119,6 +121,7 @@ void Library::WatcherInitialised() {
|
||||
|
||||
watcher->set_backend(backend_);
|
||||
watcher->set_task_manager(task_manager_);
|
||||
watcher->set_filesystem_watcher(FileSystemWatcherInterface::Create());
|
||||
|
||||
connect(backend_, SIGNAL(DirectoryDiscovered(Directory,SubdirectoryList)),
|
||||
watcher, SLOT(AddDirectory(Directory,SubdirectoryList)));
|
||||
|
@ -16,12 +16,13 @@
|
||||
*/
|
||||
|
||||
#include "librarywatcher.h"
|
||||
|
||||
#include "librarybackend.h"
|
||||
#include "core/filesystemwatcherinterface.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/taskmanager.h"
|
||||
#include "playlistparsers/cueparser.h"
|
||||
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QDateTime>
|
||||
#include <QDirIterator>
|
||||
#include <QtDebug>
|
||||
@ -48,6 +49,7 @@ LibraryWatcher::LibraryWatcher(QObject* parent)
|
||||
: QObject(parent),
|
||||
backend_(NULL),
|
||||
task_manager_(NULL),
|
||||
fs_watcher_(NULL),
|
||||
stop_requested_(false),
|
||||
scan_on_startup_(true),
|
||||
monitor_(true),
|
||||
@ -113,7 +115,7 @@ LibraryWatcher::ScanTransaction::~ScanTransaction() {
|
||||
if (watcher_->monitor_) {
|
||||
// Watch the new subdirectories
|
||||
foreach (const Subdirectory& subdir, new_subdirs) {
|
||||
watcher_->AddWatch(watcher_->watched_dirs_[dir_].watcher, subdir.path);
|
||||
watcher_->AddWatch(subdir.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -183,8 +185,6 @@ SubdirectoryList LibraryWatcher::ScanTransaction::GetAllSubdirs() {
|
||||
void LibraryWatcher::AddDirectory(const Directory& dir, const SubdirectoryList& subdirs) {
|
||||
DirData data;
|
||||
data.dir = dir;
|
||||
data.watcher = new QFileSystemWatcher(this);
|
||||
connect(data.watcher, SIGNAL(directoryChanged(QString)), SLOT(DirectoryChanged(QString)));
|
||||
watched_dirs_[dir.id] = data;
|
||||
|
||||
if (subdirs.isEmpty()) {
|
||||
@ -207,7 +207,7 @@ void LibraryWatcher::AddDirectory(const Directory& dir, const SubdirectoryList&
|
||||
ScanSubdirectory(subdir.path, subdir, &transaction);
|
||||
|
||||
if (monitor_)
|
||||
AddWatch(data.watcher, subdir.path);
|
||||
AddWatch(subdir.path);
|
||||
}
|
||||
}
|
||||
|
||||
@ -546,18 +546,16 @@ uint LibraryWatcher::GetMtimeForCue(const QString& cue_path) {
|
||||
: 0;
|
||||
}
|
||||
|
||||
void LibraryWatcher::AddWatch(QFileSystemWatcher* w, const QString& path) {
|
||||
void LibraryWatcher::AddWatch(const QString& path) {
|
||||
if (!QFile::exists(path))
|
||||
return;
|
||||
|
||||
w->addPath(path);
|
||||
connect(fs_watcher_, SIGNAL(PathChanged(const QString&)), this,
|
||||
SLOT(DirectoryChanged(const QString&)), Qt::UniqueConnection);
|
||||
fs_watcher_->AddPath(path);
|
||||
}
|
||||
|
||||
void LibraryWatcher::RemoveDirectory(const Directory& dir) {
|
||||
if (watched_dirs_.contains(dir.id)) {
|
||||
delete watched_dirs_[dir.id].watcher;
|
||||
}
|
||||
|
||||
rescan_queue_.remove(dir.id);
|
||||
watched_dirs_.remove(dir.id);
|
||||
}
|
||||
@ -575,13 +573,9 @@ bool LibraryWatcher::FindSongByPath(const SongList& list, const QString& path, S
|
||||
|
||||
void LibraryWatcher::DirectoryChanged(const QString &subdir) {
|
||||
// Find what dir it was in
|
||||
QFileSystemWatcher* watcher = qobject_cast<QFileSystemWatcher*>(sender());
|
||||
if (!watcher)
|
||||
return;
|
||||
|
||||
Directory dir;
|
||||
foreach (const DirData& info, watched_dirs_) {
|
||||
if (info.watcher == watcher)
|
||||
if (subdir.startsWith(info.dir.path))
|
||||
dir = info.dir;
|
||||
}
|
||||
|
||||
@ -689,7 +683,7 @@ void LibraryWatcher::ReloadSettings() {
|
||||
s.beginGroup(kSettingsGroup);
|
||||
scan_on_startup_ = s.value("startup_scan", true).toBool();
|
||||
monitor_ = s.value("monitor", true).toBool();
|
||||
|
||||
|
||||
best_image_filters_.clear();
|
||||
QStringList filters = s.value("cover_art_patterns",
|
||||
QStringList() << "front" << "cover").toStringList();
|
||||
@ -698,18 +692,15 @@ void LibraryWatcher::ReloadSettings() {
|
||||
if (!s.isEmpty())
|
||||
best_image_filters_ << s;
|
||||
}
|
||||
|
||||
|
||||
if (!monitor_ && was_monitoring_before) {
|
||||
// Remove all directories from all QFileSystemWatchers
|
||||
foreach (const DirData& data, watched_dirs_.values()) {
|
||||
data.watcher->removePaths(data.watcher->directories());
|
||||
}
|
||||
// TODO: Remove all directories from watcher.
|
||||
} else if (monitor_ && !was_monitoring_before) {
|
||||
// Add all directories to all QFileSystemWatchers again
|
||||
foreach (const DirData& data, watched_dirs_.values()) {
|
||||
SubdirectoryList subdirs = backend_->SubdirsInDirectory(data.dir.id);
|
||||
foreach (const Subdirectory& subdir, subdirs) {
|
||||
AddWatch(data.watcher, subdir.path);
|
||||
AddWatch(subdir.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ class QFileSystemWatcher;
|
||||
class QTimer;
|
||||
|
||||
class CueParser;
|
||||
class FileSystemWatcherInterface;
|
||||
class LibraryBackend;
|
||||
class TaskManager;
|
||||
|
||||
@ -42,8 +43,9 @@ class LibraryWatcher : public QObject {
|
||||
|
||||
void set_backend(LibraryBackend* backend) { backend_ = backend; }
|
||||
void set_task_manager(TaskManager* task_manager) { task_manager_ = task_manager; }
|
||||
void set_filesystem_watcher(FileSystemWatcherInterface* watcher) { fs_watcher_ = watcher; }
|
||||
void set_device_name(const QString& device_name) { device_name_ = device_name; }
|
||||
|
||||
|
||||
void IncrementalScanAsync();
|
||||
void FullScanAsync();
|
||||
void SetRescanPausedAsync(bool pause);
|
||||
@ -144,7 +146,7 @@ class LibraryWatcher : public QObject {
|
||||
inline static QString DirectoryPart( const QString &fileName );
|
||||
QString PickBestImage(const QStringList& images);
|
||||
QString ImageForSong(const QString& path, QMap<QString, QStringList>& album_art);
|
||||
void AddWatch(QFileSystemWatcher* w, const QString& path);
|
||||
void AddWatch(const QString& path);
|
||||
uint GetMtimeForCue(const QString& cue_path);
|
||||
void PerformScan(bool incremental, bool ignore_mtimes);
|
||||
|
||||
@ -172,20 +174,21 @@ class LibraryWatcher : public QObject {
|
||||
// One of these gets stored for each Directory we're watching
|
||||
struct DirData {
|
||||
Directory dir;
|
||||
QFileSystemWatcher* watcher;
|
||||
};
|
||||
|
||||
LibraryBackend* backend_;
|
||||
TaskManager* task_manager_;
|
||||
QString device_name_;
|
||||
|
||||
|
||||
FileSystemWatcherInterface* fs_watcher_;
|
||||
|
||||
/* A list of words use to try to identify the (likely) best image
|
||||
* found in an directory to use as cover artwork.
|
||||
* e.g. using ["front", "cover"] would identify front.jpg and
|
||||
* exclude back.jpg.
|
||||
*/
|
||||
QStringList best_image_filters_;
|
||||
|
||||
|
||||
bool stop_requested_;
|
||||
bool scan_on_startup_;
|
||||
bool monitor_;
|
||||
|
@ -16,14 +16,18 @@
|
||||
*/
|
||||
|
||||
#include "musicdnsclient.h"
|
||||
#include "core/network.h"
|
||||
|
||||
#include <QBuffer>
|
||||
#include <QCoreApplication>
|
||||
#include <QNetworkReply>
|
||||
#include <QXmlStreamReader>
|
||||
#include <QtDebug>
|
||||
|
||||
const char* MusicDnsClient::kClientId = "c44f70e49000dd7c0d1388bff2bf4152";
|
||||
#include "core/logging.h"
|
||||
#include "core/network.h"
|
||||
|
||||
//const char* MusicDnsClient::kClientId = "c44f70e49000dd7c0d1388bff2bf4152";
|
||||
const char* MusicDnsClient::kClientId = "0736ac2cd889ef77f26f6b5e3fb8a09c";
|
||||
const char* MusicDnsClient::kUrl = "http://ofa.musicdns.org/ofa/1/track";
|
||||
const int MusicDnsClient::kDefaultTimeout = 5000; // msec
|
||||
|
||||
@ -49,10 +53,12 @@ void MusicDnsClient::Start(int id, const QString& fingerprint, int duration_msec
|
||||
<< Param("cvr", QString("%1 %2").arg(QCoreApplication::applicationName(),
|
||||
QCoreApplication::applicationVersion()))
|
||||
<< Param("dur", QString::number(duration_msec))
|
||||
<< Param("lkt", "1")
|
||||
<< Param("fmt", "unknown")
|
||||
<< Param("fpt", fingerprint)
|
||||
<< Param("gnr", "unknown")
|
||||
<< Param("rmd", "1")
|
||||
<< Param("rmt", "0")
|
||||
<< Param("tnm", "0")
|
||||
<< Param("ttl", "unknown")
|
||||
<< Param("yrr", "0");
|
||||
@ -61,6 +67,8 @@ void MusicDnsClient::Start(int id, const QString& fingerprint, int duration_msec
|
||||
url.setQueryItems(parameters);
|
||||
QNetworkRequest req(url);
|
||||
|
||||
qLog(Debug) << url;
|
||||
|
||||
QNetworkReply* reply = network_->get(req);
|
||||
connect(reply, SIGNAL(finished()), SLOT(RequestFinished()));
|
||||
requests_[reply] = id;
|
||||
@ -90,12 +98,19 @@ void MusicDnsClient::RequestFinished() {
|
||||
|
||||
int id = requests_.take(reply);
|
||||
|
||||
qLog(Debug) << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
||||
|
||||
if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != 200) {
|
||||
emit Finished(id, QString());
|
||||
return;
|
||||
}
|
||||
|
||||
QXmlStreamReader reader(reply);
|
||||
QByteArray data = reply->readAll();
|
||||
qLog(Debug) << data;
|
||||
QBuffer buffer(&data);
|
||||
buffer.open(QIODevice::ReadOnly);
|
||||
|
||||
QXmlStreamReader reader(&buffer);
|
||||
while (!reader.atEnd()) {
|
||||
if (reader.readNext() == QXmlStreamReader::StartElement && reader.name() == "puid") {
|
||||
QString puid = reader.attributes().value("id").toString();
|
||||
|
Loading…
Reference in New Issue
Block a user