Includes, comments and bugfixes

- Fix includes
- Use common regex (Song::kCoverRemoveDisc) for removing Disc/CD from album
- Remove Disc/CD from album when creating hash
- Make imobiledevice support compile
- Fix setting device on windows
This commit is contained in:
Jonas Kvinge
2018-05-01 00:41:33 +02:00
parent fccbd6790c
commit e337b7933b
518 changed files with 7003 additions and 4693 deletions

View File

@@ -15,6 +15,11 @@
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QObject>
#include <QList>
#include <QTimer>
#include <QGenericArgument>
#include "closure.h"
#include "core/timeconstants.h"

View File

@@ -18,15 +18,20 @@
#ifndef CLOSURE_H
#define CLOSURE_H
#include <chrono>
#include <functional>
#include <memory>
#include <chrono>
#include <QtGlobal>
#include <QObject>
#include <QFuture>
#include <QFutureWatcher>
#include <QMetaObject>
#include <QMetaMethod>
#include <QObject>
#include <QSharedPointer>
#include <QByteArray>
#include <QString>
#include <QList>
#include <QTimer>
namespace _detail {
@@ -40,11 +45,11 @@ class ClosureBase {
virtual void Invoke() = 0;
// Tests only.
ObjectHelper* helper() const;
ObjectHelper *helper() const;
protected:
explicit ClosureBase(ObjectHelper*);
ObjectHelper* helper_;
ObjectHelper *helper_;
private:
Q_DISABLE_COPY(ClosureBase);
@@ -56,7 +61,7 @@ class ClosureBase {
class ObjectHelper : public QObject {
Q_OBJECT
public:
ObjectHelper(QObject* parent, const char* signal, ClosureBase* closure);
ObjectHelper(QObject *parent, const char *signal, ClosureBase *closure);
private slots:
void Invoked();
@@ -72,12 +77,12 @@ class ObjectHelper : public QObject {
void Unpack(QList<QGenericArgument>*);
template <typename Arg>
void Unpack(QList<QGenericArgument>* list, const Arg& arg) {
void Unpack(QList<QGenericArgument> *list, const Arg &arg) {
list->append(Q_ARG(Arg, arg));
}
template <typename Head, typename... Tail>
void Unpack(QList<QGenericArgument>* list, const Head& head, const Tail&... tail) {
void Unpack(QList<QGenericArgument> *list, const Head &head, const Tail&... tail) {
Unpack(list, head);
Unpack(list, tail...);
}
@@ -86,16 +91,16 @@ template <typename... Args>
class Closure : public ClosureBase {
public:
Closure(
QObject* sender,
const char* signal,
QObject* receiver,
const char* slot,
QObject *sender,
const char *signal,
QObject *receiver,
const char *slot,
const Args&... args)
: ClosureBase(new ObjectHelper(sender, signal, this)),
// std::bind is the easiest way to store an argument list.
function_(std::bind(&Closure<Args...>::Call, this, args...)),
receiver_(receiver) {
const QMetaObject* meta_receiver = receiver->metaObject();
const QMetaObject *meta_receiver = receiver->metaObject();
QByteArray normalised_slot = QMetaObject::normalizedSignature(slot + 1);
const int index = meta_receiver->indexOfSlot(normalised_slot.constData());
Q_ASSERT(index != -1);
@@ -127,7 +132,7 @@ class Closure : public ClosureBase {
}
std::function<void()> function_;
QObject* receiver_;
QObject *receiver_;
QMetaMethod slot_;
};
@@ -136,9 +141,9 @@ class SharedClosure : public Closure<Args...> {
public:
SharedClosure(
QSharedPointer<T> sender,
const char* signal,
QObject* receiver,
const char* slot,
const char *signal,
QObject *receiver,
const char *slot,
const Args&... args)
: Closure<Args...>(
sender.data(),
@@ -155,8 +160,7 @@ class SharedClosure : public Closure<Args...> {
class CallbackClosure : public ClosureBase {
public:
CallbackClosure(QObject* sender, const char* signal,
std::function<void()> callback);
CallbackClosure(QObject *sender, const char *signal, std::function<void()> callback);
virtual void Invoke();
@@ -167,11 +171,11 @@ class CallbackClosure : public ClosureBase {
} // namespace _detail
template <typename... Args>
_detail::ClosureBase* NewClosure(
QObject* sender,
const char* signal,
QObject* receiver,
const char* slot,
_detail::ClosureBase *NewClosure(
QObject *sender,
const char *signal,
QObject *receiver,
const char *slot,
const Args&... args) {
return new _detail::Closure<Args...>(
sender, signal, receiver, slot, args...);
@@ -179,64 +183,64 @@ _detail::ClosureBase* NewClosure(
// QSharedPointer variant
template <typename T, typename... Args>
_detail::ClosureBase* NewClosure(
_detail::ClosureBase *NewClosure(
QSharedPointer<T> sender,
const char* signal,
QObject* receiver,
const char* slot,
const char *signal,
QObject *receiver,
const char *slot,
const Args&... args) {
return new _detail::SharedClosure<T, Args...>(
sender, signal, receiver, slot, args...);
}
_detail::ClosureBase* NewClosure(QObject* sender, const char* signal, std::function<void()> callback);
_detail::ClosureBase *NewClosure(QObject *sender, const char *signal, std::function<void()> callback);
template <typename... Args>
_detail::ClosureBase* NewClosure(QObject* sender, const char* signal, std::function<void(Args...)> callback, const Args&... args) {
_detail::ClosureBase *NewClosure(QObject *sender, const char *signal, std::function<void(Args...)> callback, const Args&... args) {
return NewClosure(sender, signal, std::bind(callback, args...));
}
template <typename... Args>
_detail::ClosureBase* NewClosure(
QObject* sender,
const char* signal,
_detail::ClosureBase *NewClosure(
QObject *sender,
const char *signal,
void (*callback)(Args...),
const Args&... args) {
return NewClosure(sender, signal, std::bind(callback, args...));
}
template <typename T, typename Unused, typename... Args>
_detail::ClosureBase* NewClosure(
QObject* sender,
const char* signal,
T* receiver, Unused (T::*callback)(Args...),
_detail::ClosureBase *NewClosure(
QObject *sender,
const char *signal,
T *receiver, Unused (T::*callback)(Args...),
const Args&... args) {
return NewClosure(sender, signal, std::bind(callback, receiver, args...));
}
template <typename T, typename... Args>
_detail::ClosureBase* NewClosure(QFuture<T> future, QObject* receiver, const char* slot, const Args&... args) {
QFutureWatcher<T>* watcher = new QFutureWatcher<T>;
_detail::ClosureBase *NewClosure(QFuture<T> future, QObject *receiver, const char *slot, const Args&... args) {
QFutureWatcher<T> *watcher = new QFutureWatcher<T>;
watcher->setFuture(future);
QObject::connect(watcher, SIGNAL(finished()), watcher, SLOT(deleteLater()));
return NewClosure(watcher, SIGNAL(finished()), receiver, slot, args...);
}
template <typename T, typename F, typename... Args>
_detail::ClosureBase* NewClosure(QFuture<T> future, const F& callback, const Args&... args) {
QFutureWatcher<T>* watcher = new QFutureWatcher<T>;
_detail::ClosureBase *NewClosure(QFuture<T> future, const F &callback, const Args&... args) {
QFutureWatcher<T> *watcher = new QFutureWatcher<T>;
watcher->setFuture(future);
QObject::connect(watcher, SIGNAL(finished()), watcher, SLOT(deleteLater()));
return NewClosure(watcher, SIGNAL(finished()), callback, args...);
}
void DoAfter(QObject* receiver, const char* slot, int msec);
void DoAfter(QObject *receiver, const char *slot, int msec);
void DoAfter(std::function<void()> callback, std::chrono::milliseconds msec);
void DoInAMinuteOrSo(QObject* receiver, const char* slot);
void DoInAMinuteOrSo(QObject *receiver, const char *slot);
template <typename R, typename P>
void DoAfter(std::function<void()> callback, std::chrono::duration<R, P> duration) {
QTimer* timer = new QTimer;
QTimer *timer = new QTimer;
timer->setSingleShot(true);
NewClosure(timer, SIGNAL(timeout()), callback);
QObject::connect(timer, SIGNAL(timeout()), timer, SLOT(deleteLater()));

View File

@@ -55,9 +55,7 @@ class ThreadFunctorBase : public QFutureInterface<ReturnType>, public QRunnable
this->reportStarted();
Q_ASSERT(thread_pool);
QFuture<ReturnType> future = this->future();
thread_pool->start(this, 0 /* priority: currently we do not support
changing the priority. Might be added later
if needed */);
thread_pool->start(this, 0 /* priority: currently we do not support changing the priority. Might be added later if needed */);
return future;
}
@@ -67,8 +65,7 @@ class ThreadFunctorBase : public QFutureInterface<ReturnType>, public QRunnable
template <typename ReturnType, typename... Args>
class ThreadFunctor : public ThreadFunctorBase<ReturnType> {
public:
ThreadFunctor(std::function<ReturnType (Args...)> function,
Args... args)
ThreadFunctor(std::function<ReturnType (Args...)> function, Args... args)
: function_(std::bind(function, args...)) {
}
@@ -85,8 +82,7 @@ class ThreadFunctor : public ThreadFunctorBase<ReturnType> {
template <typename... Args>
class ThreadFunctor <void, Args...> : public ThreadFunctorBase<void> {
public:
ThreadFunctor(std::function<void (Args...)> function,
Args... args)
ThreadFunctor(std::function<void (Args...)> function, Args... args)
: function_(std::bind(function, args...)) {
}
@@ -107,30 +103,20 @@ namespace ConcurrentRun {
// Empty argument form.
template <typename ReturnType>
QFuture<ReturnType> Run(
QThreadPool* threadpool,
std::function<ReturnType ()> function) {
QFuture<ReturnType> Run(QThreadPool* threadpool, std::function<ReturnType ()> function) {
return (new ThreadFunctor<ReturnType>(function))->Start(threadpool);
}
// Function object with arguments form.
template <typename ReturnType, typename... Args>
QFuture<ReturnType> Run(
QThreadPool* threadpool,
std::function<ReturnType (Args...)> function,
const Args&... args) {
return (new ThreadFunctor<ReturnType, Args...>(
function, args...))->Start(threadpool);
QFuture<ReturnType> Run(QThreadPool* threadpool, std::function<ReturnType (Args...)> function, const Args&... args) {
return (new ThreadFunctor<ReturnType, Args...>(function, args...))->Start(threadpool);
}
// Support passing C function pointers instead of function objects.
template <typename ReturnType, typename... Args>
QFuture<ReturnType> Run(
QThreadPool* threadpool,
ReturnType (*function) (Args...),
const Args&... args) {
return Run(
threadpool, std::function<ReturnType (Args...)>(function), args...);
QFuture<ReturnType> Run(QThreadPool* threadpool, ReturnType (*function) (Args...), const Args&... args) {
return Run(threadpool, std::function<ReturnType (Args...)>(function), args...);
}
}

View File

@@ -14,21 +14,28 @@
limitations under the License.
*/
#include <glib.h>
#include <iostream>
#include <QtGlobal>
#include <QByteArray>
#include <QList>
#include <QMap>
#include <QString>
#include <QStringList>
#include <QRegExp>
#include <QDateTime>
#include <QIODevice>
#include <QtMessageHandler>
#include <QMessageLogContext>
#include <cxxabi.h>
#include <glib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#ifdef Q_OS_UNIX
#include <execinfo.h>
#endif
#include <QCoreApplication>
#include <QDateTime>
#include <QStringList>
#include <QtMessageHandler>
#include "logging.h"
namespace logging {
@@ -75,7 +82,7 @@ static void MessageHandler(QtMsgType type, const QMessageLogContext &context, co
default: level = Level_Debug; break;
}
for (const QString& line : message.split('\n')) {
for (const QString &line : message.split('\n')) {
CreateLogger(level, "unknown", -1) << line.toLocal8Bit().constData();
}

View File

@@ -18,8 +18,10 @@
#define LOGGING_H
#include <chrono>
#include <string>
#include <QtGlobal>
#include <QIODevice>
#include <QString>
#include <QDebug>
#ifdef QT_NO_DEBUG_STREAM
@@ -61,30 +63,30 @@ enum Level {
void DumpStackTrace();
QString ParsePrettyFunction(const char* pretty_function);
QString ParsePrettyFunction(const char *pretty_function);
QDebug CreateLogger(Level level, const QString &class_name, int line);
QDebug CreateLoggerFatal(int line, const char* class_name);
QDebug CreateLoggerError(int line, const char* class_name);
QDebug CreateLoggerFatal(int line, const char *class_name);
QDebug CreateLoggerError(int line, const char *class_name);
#ifdef QT_NO_WARNING_OUTPUT
QNoDebug CreateLoggerWarning(int, const char*);
#else
QDebug CreateLoggerWarning(int line, const char* class_name);
QDebug CreateLoggerWarning(int line, const char *class_name);
#endif // QT_NO_WARNING_OUTPUT
#ifdef QT_NO_DEBUG_OUTPUT
QNoDebug CreateLoggerInfo(int, const char*);
QNoDebug CreateLoggerDebug(int, const char*);
#else
QDebug CreateLoggerInfo(int line, const char* class_name);
QDebug CreateLoggerDebug(int line, const char* class_name);
QDebug CreateLoggerInfo(int line, const char *class_name);
QDebug CreateLoggerDebug(int line, const char *class_name);
#endif // QT_NO_DEBUG_OUTPUT
void GLog(const char* domain, int level, const char* message, void* user_data);
void GLog(const char *domain, int level, const char *message, void *user_data);
extern const char* kDefaultLogLevels;
extern const char *kDefaultLogLevels;
}
QDebug operator<<(QDebug debug, std::chrono::seconds secs);

View File

@@ -15,11 +15,15 @@
*/
#include "messagehandler.h"
#include "core/logging.h"
#include <QObject>
#include <QAbstractSocket>
#include <QLocalSocket>
#include <QDataStream>
#include <QIODevice>
#include <QLocalSocket>
#include <QByteArray>
#include "core/logging.h"
_MessageHandlerBase::_MessageHandlerBase(QIODevice *device, QObject *parent)
: QObject(parent),

View File

@@ -18,21 +18,21 @@
#ifndef MESSAGEHANDLER_H
#define MESSAGEHANDLER_H
#include <QBuffer>
#include <QMap>
#include <QMutex>
#include <QMutexLocker>
#include <string>
#include <QtGlobal>
#include <QObject>
#include <QSemaphore>
#include <QThread>
#include <QIODevice>
#include <QBuffer>
#include <QByteArray>
#include <QMap>
#include <QString>
#include <QLocalSocket>
#include <QAbstractSocket>
#include "core/logging.h"
#include "core/messagereply.h"
class QAbstractSocket;
class QIODevice;
class QLocalSocket;
#define QStringFromStdString(x) QString::fromUtf8(x.data(), x.size())
#define DataCommaSizeFromQString(x) x.toUtf8().constData(), x.toUtf8().length()
@@ -45,27 +45,27 @@ class _MessageHandlerBase : public QObject {
public:
// device can be NULL, in which case you must call SetDevice before writing
// any messages.
_MessageHandlerBase(QIODevice* device, QObject* parent);
_MessageHandlerBase(QIODevice *device, QObject *parent);
void SetDevice(QIODevice* device);
void SetDevice(QIODevice *device);
// After this is true, messages cannot be sent to the handler any more.
bool is_device_closed() const { return is_device_closed_; }
protected slots:
void WriteMessage(const QByteArray& data);
void WriteMessage(const QByteArray &data);
void DeviceReadyRead();
virtual void DeviceClosed();
protected:
virtual bool RawMessageArrived(const QByteArray& data) = 0;
virtual bool RawMessageArrived(const QByteArray &data) = 0;
virtual void AbortAll() = 0;
protected:
typedef bool (QAbstractSocket::*FlushAbstractSocket)();
typedef bool (QLocalSocket::*FlushLocalSocket)();
QIODevice* device_;
QIODevice *device_;
FlushAbstractSocket flush_abstract_socket_;
FlushLocalSocket flush_local_socket_;
@@ -82,7 +82,7 @@ protected:
template <typename MT>
class AbstractMessageHandler : public _MessageHandlerBase {
public:
AbstractMessageHandler(QIODevice* device, QObject* parent);
AbstractMessageHandler(QIODevice *device, QObject *parent);
~AbstractMessageHandler() { AbortAll(); }
typedef MT MessageType;
@@ -90,27 +90,27 @@ public:
// Serialises the message and writes it to the socket. This version MUST be
// called from the thread in which the AbstractMessageHandler was created.
void SendMessage(const MessageType& message);
void SendMessage(const MessageType &message);
// Serialises the message and writes it to the socket. This version may be
// called from any thread.
void SendMessageAsync(const MessageType& message);
void SendMessageAsync(const MessageType &message);
// Sends the request message inside and takes ownership of the MessageReply.
// The MessageReply's Finished() signal will be emitted when a reply arrives
// with the same ID. Must be called from my thread.
void SendRequest(ReplyType* reply);
void SendRequest(ReplyType *reply);
// Sets the "id" field of reply to the same as the request, and sends the
// reply on the socket. Used on the worker side.
void SendReply(const MessageType& request, MessageType* reply);
void SendReply(const MessageType &request, MessageType *reply);
protected:
// Called when a message is received from the socket.
virtual void MessageArrived(const MessageType& message) {}
virtual void MessageArrived(const MessageType &message) {}
// _MessageHandlerBase
bool RawMessageArrived(const QByteArray& data);
bool RawMessageArrived(const QByteArray &data);
void AbortAll();
private:
@@ -118,12 +118,11 @@ private:
};
template <typename MT>
AbstractMessageHandler<MT>::AbstractMessageHandler(QIODevice* device,
QObject* parent)
AbstractMessageHandler<MT>::AbstractMessageHandler(QIODevice *device, QObject *parent)
: _MessageHandlerBase(device, parent) {}
template <typename MT>
void AbstractMessageHandler<MT>::SendMessage(const MessageType& message) {
void AbstractMessageHandler<MT>::SendMessage(const MessageType &message) {
Q_ASSERT(QThread::currentThread() == thread());
std::string data = message.SerializeAsString();
@@ -131,33 +130,32 @@ void AbstractMessageHandler<MT>::SendMessage(const MessageType& message) {
}
template <typename MT>
void AbstractMessageHandler<MT>::SendMessageAsync(const MessageType& message) {
void AbstractMessageHandler<MT>::SendMessageAsync(const MessageType &message) {
std::string data = message.SerializeAsString();
metaObject()->invokeMethod(this, "WriteMessage", Qt::QueuedConnection,
Q_ARG(QByteArray, QByteArray(data.data(), data.size())));
}
template<typename MT>
void AbstractMessageHandler<MT>::SendRequest(ReplyType* reply) {
void AbstractMessageHandler<MT>::SendRequest(ReplyType *reply) {
pending_replies_[reply->id()] = reply;
SendMessage(reply->request_message());
}
template<typename MT>
void AbstractMessageHandler<MT>::SendReply(const MessageType& request,
MessageType* reply) {
void AbstractMessageHandler<MT>::SendReply(const MessageType &request, MessageType *reply) {
reply->set_id(request.id());
SendMessage(*reply);
}
template<typename MT>
bool AbstractMessageHandler<MT>::RawMessageArrived(const QByteArray& data) {
bool AbstractMessageHandler<MT>::RawMessageArrived(const QByteArray &data) {
MessageType message;
if (!message.ParseFromArray(data.constData(), data.size())) {
return false;
}
ReplyType* reply = pending_replies_.take(message.id());
ReplyType *reply = pending_replies_.take(message.id());
if (reply) {
// This is a reply to a message that we created earlier.
@@ -171,7 +169,7 @@ bool AbstractMessageHandler<MT>::RawMessageArrived(const QByteArray& data) {
template<typename MT>
void AbstractMessageHandler<MT>::AbortAll() {
for (ReplyType* reply : pending_replies_) {
for (ReplyType *reply : pending_replies_) {
reply->Abort();
}
pending_replies_.clear();

View File

@@ -17,6 +17,11 @@
#include "messagereply.h"
#include <QObject>
#include <QtDebug>
#include "core/logging.h"
_MessageReplyBase::_MessageReplyBase(QObject *parent)
: QObject(parent), finished_(false), success_(false) {}

View File

@@ -18,26 +18,26 @@
#ifndef MESSAGEREPLY_H
#define MESSAGEREPLY_H
#include <QtGlobal>
#include <QObject>
#include <QSemaphore>
#include <QString>
#include "core/logging.h"
// Base QObject for a reply future class that is returned immediately for
// requests that will occur in the background. Similar to QNetworkReply.
// Use MessageReply instead.
// Base QObject for a reply future class that is returned immediately for requests that will occur in the background.
// Similar to QNetworkReply. Use MessageReply instead.
class _MessageReplyBase : public QObject {
Q_OBJECT
public:
_MessageReplyBase(QObject* parent = nullptr);
_MessageReplyBase(QObject *parent = nullptr);
virtual int id() const = 0;
bool is_finished() const { return finished_; }
bool is_successful() const { return success_; }
// Waits for the reply to finish by waiting on a semaphore. Never call this
// from the MessageHandler's thread or it will block forever.
// Waits for the reply to finish by waiting on a semaphore. Never call this from the MessageHandler's thread or it will block forever.
// Returns true if the call was successful.
bool WaitForFinished();
@@ -58,7 +58,7 @@ protected:
template <typename MessageType>
class MessageReply : public _MessageReplyBase {
public:
MessageReply(const MessageType& request_message, QObject* parent = nullptr);
MessageReply(const MessageType& request_message, QObject *parent = nullptr);
int id() const { return request_message_.id(); }
const MessageType& request_message() const { return request_message_; }
@@ -73,8 +73,7 @@ private:
template<typename MessageType>
MessageReply<MessageType>::MessageReply(const MessageType& request_message,
QObject* parent)
MessageReply<MessageType>::MessageReply(const MessageType& request_message, QObject *parent)
: _MessageReplyBase(parent)
{
request_message_.MergeFrom(request_message);
@@ -94,4 +93,3 @@ void MessageReply<MessageType>::SetReply(const MessageType& message) {
}
#endif // MESSAGEREPLY_H

View File

@@ -17,6 +17,7 @@
#include "waitforsignal.h"
#include <QObject>
#include <QEventLoop>
void WaitForSignal(QObject *sender, const char *signal) {

View File

@@ -15,6 +15,8 @@
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QObject>
#include "workerpool.h"
_WorkerPoolBase::_WorkerPoolBase(QObject *parent) : QObject(parent) {}

View File

@@ -18,32 +18,37 @@
#ifndef WORKERPOOL_H
#define WORKERPOOL_H
#include <QAtomicInt>
#include <QCoreApplication>
#include <QFile>
#include <QLocalServer>
#include <QLocalSocket>
#include <QMutex>
#include <stddef.h>
#include <QtGlobal>
#include <QObject>
#include <QCoreApplication>
#include <QThread>
#include <QMutex>
#include <QProcess>
#include <QQueue>
#include <QThread>
#include <QFile>
#include <QList>
#include <QLocalServer>
#include <QLocalSocket>
#include <QString>
#include <QStringList>
#include <QAtomicInt>
#include "core/closure.h"
#include "core/logging.h"
class QLocalSocket;
// Base class containing signals and slots - required because moc doesn't do
// templated objects.
// Base class containing signals and slots - required because moc doesn't do templated objects.
class _WorkerPoolBase : public QObject {
Q_OBJECT
public:
_WorkerPoolBase(QObject* parent = nullptr);
_WorkerPoolBase(QObject *parent = nullptr);
signals:
// Emitted when a worker failed to start. This usually happens when the
// worker wasn't found, or couldn't be executed.
// Emitted when a worker failed to start. This usually happens when the worker wasn't found, or couldn't be executed.
void WorkerFailedToStart();
protected slots:
@@ -54,45 +59,41 @@ protected slots:
};
// Manages a pool of one or more external processes. A local socket server is
// started for each process, and the address is passed to the process as
// argv[1]. The process is expected to connect back to the socket server, and
// when it does a HandlerType is created for it.
// Manages a pool of one or more external processes.
// A local socket server is started for each process, and the address is passed to the process as argv[1].
// The process is expected to connect back to the socket server, and when it does a HandlerType is created for it.
// Instances of HandlerType are created in the WorkerPool's thread.
template <typename HandlerType>
class WorkerPool : public _WorkerPoolBase {
public:
WorkerPool(QObject* parent = nullptr);
WorkerPool(QObject *parent = nullptr);
~WorkerPool();
typedef typename HandlerType::MessageType MessageType;
typedef typename HandlerType::ReplyType ReplyType;
// Sets the name of the worker executable. This is looked for first in the
// current directory, and then in $PATH. You must call this before calling
// Start().
void SetExecutableName(const QString& executable_name);
// Sets the name of the worker executable. This is looked for first in the current directory, and then in $PATH.
// You must call this before calling Start().
void SetExecutableName(const QString &executable_name);
// Sets the number of worker process to use. Defaults to
// 1 <= (processors / 2) <= 2.
// Sets the number of worker process to use. Defaults to 1 <= (processors / 2) <= 2.
void SetWorkerCount(int count);
// Sets the prefix to use for the local server (on unix this is a named pipe
// in /tmp). Defaults to QApplication::applicationName(). A random number
// is appended to this name when creating each server.
void SetLocalServerName(const QString& local_server_name);
// Sets the prefix to use for the local server (on unix this is a named pipe in /tmp).
// Defaults to QApplication::applicationName().
// A random number is appended to this name when creating each server.
void SetLocalServerName(const QString &local_server_name);
// Starts all workers.
void Start();
// Fills in the message's "id" field and creates a reply future. The message
// is queued and the WorkerPool's thread will send it to the next available
// worker. Can be called from any thread.
ReplyType* SendMessageWithReply(MessageType* message);
// Fills in the message's "id" field and creates a reply future.
// The message is queued and the WorkerPool's thread will send it to the next available worker.
// Can be called from any thread.
ReplyType *SendMessageWithReply(MessageType *message);
protected:
// These are all reimplemented slots, they are called on the WorkerPool's
// thread.
// These are all reimplemented slots, they are called on the WorkerPool's thread.
void DoStart();
void NewConnection();
void ProcessError(QProcess::ProcessError error);
@@ -105,14 +106,14 @@ private:
QLocalServer *local_server_;
QLocalSocket *local_socket_;
QProcess *process_;
HandlerType* handler_;
HandlerType *handler_;
};
// Must only ever be called on my thread.
void StartOneWorker(Worker* worker);
void StartOneWorker(Worker *worker);
template <typename T>
Worker* FindWorker(T Worker::*member, T value) {
Worker *FindWorker(T Worker::*member, T value) {
for (typename QList<Worker>::iterator it = workers_.begin() ;
it != workers_.end() ; ++it) {
if ((*it).*member == value) {
@@ -123,7 +124,7 @@ private:
}
template <typename T>
void DeleteQObjectPointerLater(T** p) {
void DeleteQObjectPointerLater(T **p) {
if (*p) {
(*p)->deleteLater();
*p = NULL;
@@ -131,13 +132,11 @@ private:
}
// Creates a new reply future for the request with the next sequential ID,
// and sets the request's ID to the ID of the reply. Can be called from any
// thread
ReplyType* NewReply(MessageType* message);
// and sets the request's ID to the ID of the reply. Can be called from any thread
ReplyType *NewReply(MessageType *message);
// Returns the next handler, or NULL if there isn't one. Must be called from
// my thread.
HandlerType* NextHandler() const;
// Returns the next handler, or NULL if there isn't one. Must be called from my thread.
HandlerType *NextHandler() const;
private:
QString local_server_name_;
@@ -156,7 +155,7 @@ private:
template <typename HandlerType>
WorkerPool<HandlerType>::WorkerPool(QObject* parent)
WorkerPool<HandlerType>::WorkerPool(QObject *parent)
: _WorkerPoolBase(parent),
next_worker_(0),
next_id_(0)
@@ -170,7 +169,7 @@ WorkerPool<HandlerType>::WorkerPool(QObject* parent)
template <typename HandlerType>
WorkerPool<HandlerType>::~WorkerPool() {
for (const Worker& worker : workers_) {
for (const Worker &worker : workers_) {
if (worker.local_socket_ && worker.process_) {
disconnect(worker.process_, SIGNAL(error(QProcess::ProcessError)), this, SLOT(ProcessError(QProcess::ProcessError)));
@@ -190,7 +189,7 @@ WorkerPool<HandlerType>::~WorkerPool() {
}
}
for (ReplyType* reply : message_queue_) {
for (ReplyType *reply : message_queue_) {
reply->Abort();
}
}
@@ -202,13 +201,13 @@ void WorkerPool<HandlerType>::SetWorkerCount(int count) {
}
template <typename HandlerType>
void WorkerPool<HandlerType>::SetLocalServerName(const QString& local_server_name) {
void WorkerPool<HandlerType>::SetLocalServerName(const QString &local_server_name) {
Q_ASSERT(workers_.isEmpty());
local_server_name_ = local_server_name;
}
template <typename HandlerType>
void WorkerPool<HandlerType>::SetExecutableName(const QString& executable_name) {
void WorkerPool<HandlerType>::SetExecutableName(const QString &executable_name) {
Q_ASSERT(workers_.isEmpty());
executable_name_ = executable_name;
}
@@ -233,7 +232,7 @@ void WorkerPool<HandlerType>::DoStart() {
search_path << qApp->applicationDirPath() + "/../PlugIns";
#endif
for (const QString& path_prefix : search_path) {
for (const QString &path_prefix : search_path) {
const QString executable_path = path_prefix + "/" + executable_name_;
if (QFile::exists(executable_path)) {
executable_path_ = executable_path;
@@ -290,7 +289,7 @@ void WorkerPool<HandlerType>::NewConnection() {
QLocalServer *server = qobject_cast<QLocalServer*>(sender());
// Find the worker with this server.
Worker* worker = FindWorker(&Worker::local_server_, server);
Worker *worker = FindWorker(&Worker::local_server_, server);
if (!worker) return;
qLog(Debug) << "Worker" << worker << "connected to" << server->fullServerName();
@@ -322,9 +321,8 @@ void WorkerPool<HandlerType>::ProcessError(QProcess::ProcessError error) {
switch (error) {
case QProcess::FailedToStart:
// Failed to start errors are bad - it usually means the worker isn't
// installed. Don't restart the process, but tell our owner, who will
// probably want to do something fatal.
// Failed to start errors are bad - it usually means the worker isn't installed.
// Don't restart the process, but tell our owner, who will probably want to do something fatal.
qLog(Error) << "Worker failed to start";
emit WorkerFailedToStart();
break;
@@ -339,7 +337,7 @@ void WorkerPool<HandlerType>::ProcessError(QProcess::ProcessError error) {
template <typename HandlerType>
typename WorkerPool<HandlerType>::ReplyType*
WorkerPool<HandlerType>::NewReply(MessageType* message) {
WorkerPool<HandlerType>::NewReply(MessageType *message) {
const int id = next_id_.fetchAndAddOrdered(1);
message->set_id(id);
@@ -348,8 +346,8 @@ WorkerPool<HandlerType>::NewReply(MessageType* message) {
template <typename HandlerType>
typename WorkerPool<HandlerType>::ReplyType*
WorkerPool<HandlerType>::SendMessageWithReply(MessageType* message) {
ReplyType* reply = NewReply(message);
WorkerPool<HandlerType>::SendMessageWithReply(MessageType *message) {
ReplyType *reply = NewReply(message);
// Add the pending reply to the queue
{
@@ -371,7 +369,7 @@ void WorkerPool<HandlerType>::SendQueuedMessages() {
ReplyType *reply = message_queue_.dequeue();
// Find a worker for this message
HandlerType* handler = NextHandler();
HandlerType *handler = NextHandler();
if (!handler) {
// No available handlers - put the message on the front of the queue.
message_queue_.prepend(reply);

View File

@@ -15,12 +15,15 @@
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*/
#include "fmpsparser.h"
#include "config.h"
#include <functional>
#include <QStringList>
#include <QtDebug>
#include <QList>
#include <QVariant>
#include <QString>
#include "fmpsparser.h"
using std::placeholders::_1;
using std::placeholders::_2;
@@ -114,8 +117,7 @@ int FMPSParser::ParseListListRef(const QStringRef &data, Result *ret) const {
return ParseContainer<';'>(data, std::bind(&FMPSParser::ParseListRef, this, _1, _2), ret);
}
// Convenience functions that take QStrings instead of QStringRefs. Use the
// QStringRef versions if possible, they're faster.
// Convenience functions that take QStrings instead of QStringRefs. Use the QStringRef versions if possible, they're faster.
int FMPSParser::ParseValue(const QString &data, QVariant *ret) const {
return ParseValueRef(QStringRef(&data), ret);
}

View File

@@ -18,8 +18,13 @@
#ifndef FMPSPARSER_H
#define FMPSPARSER_H
#include "config.h"
#include <QList>
#include <QMetaType>
#include <QVariant>
#include <QString>
#include <QRegExp>
#include <QVariantList>
class FMPSParser {
public:
@@ -30,7 +35,7 @@ public:
typedef QList<QVariantList> Result;
// Parses a FMPS value and returns true on success.
bool Parse(const QString& data);
bool Parse(const QString &data);
// Gets the result of the last successful Parse.
Result result() const { return result_; }

View File

@@ -15,50 +15,75 @@
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "tagreader.h"
#include <memory>
#include <QCoreApplication>
#include <QDateTime>
#include <QFileInfo>
#include <QNetworkAccessManager>
#include <QTextCodec>
#include <QUrl>
#include <QVector>
#include <aifffile.h>
#include <asffile.h>
#include <attachedpictureframe.h>
#include <commentsframe.h>
#include <fileref.h>
#include <audioproperties.h>
#include <flacfile.h>
#include <flacproperties.h>
#include <id3v2tag.h>
#include <mp4file.h>
#include <mp4tag.h>
#include <mpcfile.h>
#include <mpegfile.h>
#include <oggfile.h>
#ifdef TAGLIB_HAS_OPUS
#include <opusfile.h>
#endif
#include <oggflacfile.h>
#include <popularimeterframe.h>
#include <speexfile.h>
#include <tag.h>
#include <textidentificationframe.h>
#include <trueaudiofile.h>
#include <tstring.h>
#include <vorbisfile.h>
#include <wavfile.h>
#include <list>
#include <map>
#include <utility>
#include <sys/stat.h>
#include "fmpsparser.h"
#include <taglib/taglib.h>
#include <taglib/taglib_config.h>
#include <taglib/fileref.h>
#include <taglib/tbytevector.h>
#include <taglib/tfile.h>
#include <taglib/tlist.h>
#include <taglib/tstring.h>
#include <taglib/tstringlist.h>
#include <taglib/audioproperties.h>
#include <taglib/trueaudiofile.h>
#include <taglib/attachedpictureframe.h>
#include <taglib/textidentificationframe.h>
#include <taglib/xiphcomment.h>
#include <taglib/commentsframe.h>
#include <taglib/tag.h>
#include <taglib/id3v2tag.h>
#include "taglib/id3v2frame.h"
#include <taglib/flacfile.h>
#include <taglib/oggflacfile.h>
#include <taglib/flacproperties.h>
#include <taglib/flacpicture.h>
#include <taglib/vorbisfile.h>
#include <taglib/speexfile.h>
#include <taglib/wavfile.h>
#include <taglib/aifffile.h>
#include <taglib/asffile.h>
#include "taglib/asftag.h"
#include "taglib/asfattribute.h"
#include "taglib/asfproperties.h"
#include <taglib/mp4file.h>
#include <taglib/mp4tag.h>
#include "taglib/mp4item.h"
#include <taglib/mp4coverart.h>
#include <taglib/mp4properties.h>
#include <taglib/mpcfile.h>
#include <taglib/mpegfile.h>
#ifdef TAGLIB_HAS_OPUS
#include <taglib/opusfile.h>
#endif
#include <QtGlobal>
#include <QFile>
#include <QFileInfo>
#include <QList>
#include <QByteArray>
#include <QDateTime>
#include <QVariant>
#include <QString>
#include <QUrl>
#include <QTextCodec>
#include <QVector>
#include <QNetworkAccessManager>
#include <QtDebug>
#include "core/logging.h"
#include "core/messagehandler.h"
#include "fmpsparser.h"
#include "core/timeconstants.h"
// Taglib added support for FLAC pictures in 1.7.0
@@ -71,12 +96,12 @@
class FileRefFactory {
public:
virtual ~FileRefFactory() {}
virtual TagLib::FileRef *GetFileRef(const QString& filename) = 0;
virtual TagLib::FileRef *GetFileRef(const QString &filename) = 0;
};
class TagLibFileRefFactory : public FileRefFactory {
public:
virtual TagLib::FileRef *GetFileRef(const QString& filename) {
virtual TagLib::FileRef *GetFileRef(const QString &filename) {
#ifdef Q_OS_WIN32
return new TagLib::FileRef(filename.toStdWString().c_str());
#else
@@ -87,11 +112,11 @@ class TagLibFileRefFactory : public FileRefFactory {
namespace {
TagLib::String StdStringToTaglibString(const std::string& s) {
TagLib::String StdStringToTaglibString(const std::string &s) {
return TagLib::String(s.c_str(), TagLib::String::UTF8);
}
TagLib::String QStringToTaglibString(const QString& s) {
TagLib::String QStringToTaglibString(const QString &s) {
return TagLib::String(s.toUtf8().constData(), TagLib::String::UTF8);
}
@@ -508,8 +533,7 @@ bool TagReader::SaveFile(const QString &filename, const pb::tagreader::SongMetad
}
// Handle all the files which have VorbisComments (Ogg, OPUS, ...) in the same way;
// apart, so we keep specific behavior for some formats by adding another
// "else if" block above.
// apart, so we keep specific behavior for some formats by adding another "else if" block above.
if (TagLib::Ogg::XiphComment *tag = dynamic_cast<TagLib::Ogg::XiphComment*>(fileref->file()->tag())) {
SetVorbisComments(tag, song);
}
@@ -625,9 +649,7 @@ QByteArray TagReader::LoadEmbeddedArt(const QString &filename) const {
TagLib::Ogg::FieldListMap map = xiph_comment->fieldListMap();
#if TAGLIB_MAJOR_VERSION <= 1 && TAGLIB_MINOR_VERSION < 11
// Other than the below mentioned non-standard COVERART,
// METADATA_BLOCK_PICTURE
// is the proposed tag for cover pictures.
// Other than the below mentioned non-standard COVERART, METADATA_BLOCK_PICTURE is the proposed tag for cover pictures.
// (see http://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE)
if (map.contains("METADATA_BLOCK_PICTURE")) {
TagLib::StringList pict_list = map["METADATA_BLOCK_PICTURE"];
@@ -687,10 +709,10 @@ QByteArray TagReader::LoadEmbeddedArt(const QString &filename) const {
TagLib::MP4::File *aac_file = dynamic_cast<TagLib::MP4::File*>(ref.file());
if (aac_file) {
TagLib::MP4::Tag *tag = aac_file->tag();
const TagLib::MP4::ItemListMap& items = tag->itemListMap();
const TagLib::MP4::ItemListMap &items = tag->itemListMap();
TagLib::MP4::ItemListMap::ConstIterator it = items.find("covr");
if (it != items.end()) {
const TagLib::MP4::CoverArtList& art_list = it->second.toCoverArtList();
const TagLib::MP4::CoverArtList &art_list = it->second.toCoverArtList();
if (!art_list.isEmpty()) {
// Just take the first one for now

View File

@@ -18,18 +18,19 @@
#ifndef TAGREADER_H
#define TAGREADER_H
#include "config.h"
#include <string>
#include <QByteArray>
#include <QString>
#include <QNetworkAccessManager>
#include <QTextCodec>
#include <taglib/xiphcomment.h>
#include "config.h"
#include "tagreadermessages.pb.h"
class QNetworkAccessManager;
class QString;
class QTextCodec;
class QUrl;
namespace TagLib {
class FileRef;
class String;
@@ -44,15 +45,14 @@ class FileRefFactory;
/**
* This class holds all useful methods to read and write tags from/to files.
* You should not use it directly in the main process but rather use a
* TagReaderWorker process (using TagReaderClient)
* You should not use it directly in the main process but rather use a TagReaderWorker process (using TagReaderClient)
*/
class TagReader {
public:
TagReader();
void ReadFile(const QString& filename, pb::tagreader::SongMetadata *song) const;
bool SaveFile(const QString& filename, const pb::tagreader::SongMetadata &song) const;
void ReadFile(const QString &filename, pb::tagreader::SongMetadata *song) const;
bool SaveFile(const QString &filename, const pb::tagreader::SongMetadata &song) const;
bool IsMediaFile(const QString &filename) const;
QByteArray LoadEmbeddedArt(const QString &filename) const;

View File

@@ -15,16 +15,23 @@
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*/
#include "tagreaderworker.h"
#include "core/logging.h"
#include "config.h"
#include <sys/time.h>
#include <iostream>
#include <QtGlobal>
#include <QCoreApplication>
#include <QList>
#include <QLocalSocket>
#include <QSsl>
#include <QSslCertificate>
#include <QSslSocket>
#include <QStringList>
#include <QtDebug>
#include <iostream>
#include <sys/time.h>
#include "core/logging.h"
#include "tagreaderworker.h"
int main(int argc, char **argv) {

View File

@@ -15,15 +15,16 @@
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*/
#include "tagreaderworker.h"
#include "config.h"
#include <string>
#include <QCoreApplication>
#include <QDateTime>
#include <QFileInfo>
#include <QNetworkAccessManager>
#include <QTextCodec>
#include <QUrl>
#include <QObject>
#include <QIODevice>
#include <QByteArray>
#include "tagreaderworker.h"
TagReaderWorker::TagReaderWorker(QIODevice *socket, QObject *parent)
: AbstractMessageHandler<pb::tagreader::Message>(socket, parent)

View File

@@ -19,9 +19,15 @@
#define TAGREADERWORKER_H
#include "config.h"
#include <stddef.h>
#include <QObject>
#include <QIODevice>
#include "core/messagehandler.h"
#include "tagreader.h"
#include "tagreadermessages.pb.h"
#include "core/messagehandler.h"
class TagReaderWorker : public AbstractMessageHandler<pb::tagreader::Message> {
public: