diff --git a/capability.cpp b/capability.cpp
index 3aebed3..ac5182c 100644
--- a/capability.cpp
+++ b/capability.cpp
@@ -52,7 +52,10 @@ bool DeviceCapability::exchangeInfo(vita_device_t *device)
return false;
}
- VitaMTP_Data_Free_Capability(vita_capabilities); // TODO: Use this data
+ // TODO: vitamtp needs to send the full metadata info to know the expected format
+ // of thumbnails, for example. Until then lets discard the received info.
+
+ VitaMTP_Data_Free_Capability(vita_capabilities);
// Send the host's capabilities
capability_info_t *pc_capabilities = generate_pc_capability_info();
diff --git a/cmabroadcast.cpp b/cmabroadcast.cpp
new file mode 100644
index 0000000..91456c1
--- /dev/null
+++ b/cmabroadcast.cpp
@@ -0,0 +1,101 @@
+/*
+ * QCMA: Cross-platform content manager assistant for the PS Vita
+ *
+ * Copyright (C) 2013 Codestation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "cmabroadcast.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+const QString CmaBroadcast::broadcast_reply =
+ "%1\r\n"
+ "host-id:%2\r\n"
+ "host-type:%3\r\n"
+ "host-name:%4\r\n"
+ "host-mtp-protocol-version:%5\r\n"
+ "host-request-port:%6\r\n"
+ "host-wireless-protocol-version:%7\r\n";
+
+const char *CmaBroadcast::broadcast_query = "SRCH * HTTP/1.1\r\n";
+
+const char *CmaBroadcast::broadcast_ok = "HTTP/1.1 200 OK";
+const char *CmaBroadcast::broadcast_unavailable = "HTTP/1.1 503 NG";
+
+CmaBroadcast::CmaBroadcast(QObject *parent) :
+ QObject(parent)
+{
+ QSettings settings;
+ // generate a GUID if doesn't exist yet in settings
+ uuid = settings.value("guid").toString();
+ if(uuid.isEmpty()) {
+ uuid = QUuid::createUuid().toString();
+ settings.setValue("guid", uuid);
+ }
+
+ hostname = QHostInfo::localHostName();
+ setAvailable();
+
+ socket = new QUdpSocket(this);
+ socket->bind(QHostAddress::Any, QCMA_REQUEST_PORT);
+ connect(socket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
+}
+
+void CmaBroadcast::readPendingDatagrams()
+{
+ if(socket->hasPendingDatagrams()) {
+ QByteArray datagram;
+ datagram.resize(socket->pendingDatagramSize());
+
+ QHostAddress sender;
+ quint16 senderPort;
+
+ socket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
+
+ if(datagram.contains(broadcast_query)) {
+ QMutexLocker locker(&mutex);
+ socket->writeDatagram(reply.toUtf8(), sender, senderPort);
+ } else {
+ qWarning("Unknown request: %.*s\n", datagram.length(), datagram.constData());
+ }
+ }
+}
+
+void CmaBroadcast::setAvailable()
+{
+ QMutexLocker locker(&mutex);
+ reply = broadcast_reply
+ .arg(broadcast_ok, uuid, "win", hostname)
+ .arg(VITAMTP_PROTOCOL_MAX_VERSION, 8, 10, QChar('0'))
+ .arg(QCMA_REQUEST_PORT)
+ .arg(VITAMTP_WIRELESS_MAX_VERSION, 8, 10, QChar('0'));
+}
+
+void CmaBroadcast::setUnavailable()
+{
+ QMutexLocker locker(&mutex);
+ reply = broadcast_reply
+ .arg(broadcast_unavailable, uuid, "win", hostname)
+ .arg(VITAMTP_PROTOCOL_MAX_VERSION, 8, 10, QChar('0'))
+ .arg(QCMA_REQUEST_PORT)
+ .arg(VITAMTP_WIRELESS_MAX_VERSION, 8, 10, QChar('0'));
+}
diff --git a/cmabroadcast.h b/cmabroadcast.h
new file mode 100644
index 0000000..a30c98f
--- /dev/null
+++ b/cmabroadcast.h
@@ -0,0 +1,56 @@
+/*
+ * QCMA: Cross-platform content manager assistant for the PS Vita
+ *
+ * Copyright (C) 2013 Codestation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef CMABROADCAST_H
+#define CMABROADCAST_H
+
+#include
+#include
+#include
+
+#define QCMA_REQUEST_PORT 9309
+
+class CmaBroadcast : public QObject
+{
+ Q_OBJECT
+public:
+ explicit CmaBroadcast(QObject *parent = 0);
+
+private:
+ void replyBroadcast(const QByteArray &datagram);
+
+ QMutex mutex;
+ QString uuid;
+ QString reply;
+ QString hostname;
+ QUdpSocket *socket;
+ static const QString broadcast_reply;
+ static const char *broadcast_query;
+ static const char *broadcast_ok;
+ static const char *broadcast_unavailable;
+
+public slots:
+ void setAvailable();
+ void setUnavailable();
+
+private slots:
+ void readPendingDatagrams();
+};
+
+#endif // CMABROADCAST_H
diff --git a/cmaclient.cpp b/cmaclient.cpp
index 269d42e..10c6cd0 100644
--- a/cmaclient.cpp
+++ b/cmaclient.cpp
@@ -1,7 +1,28 @@
+/*
+ * QCMA: Cross-platform content manager assistant for the PS Vita
+ *
+ * Copyright (C) 2013 Codestation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
#include "cmaclient.h"
#include "capability.h"
#include "utils.h"
+#include "wirelessworker.h"
+#include "QApplication"
#include
#include
#include
@@ -10,55 +31,76 @@
#include
#include
-const metadata_t CmaClient::g_thumbmeta = {0, 0, 0, NULL, NULL, 0, 0, 0, Thumbnail, {{18, 144, 80, 0, 1, 1.0f, 2}}, NULL};
+#include
+#include
+
+metadata_t CmaClient::g_thumbmeta = {0, 0, 0, NULL, NULL, 0, 0, 0, Thumbnail, {{18, 144, 80, 0, 1, 1.0f, 2}}, NULL};
CmaClient::CmaClient(QObject *parent) :
BaseWorker(parent)
{
}
-CmaClient::CmaClient(Database *database, vita_device_t *device, QObject *parent) :
- BaseWorker(parent), db(database), device(device)
+vita_device_t *CmaClient::getDeviceConnection()
{
-}
+ int num_tries = 0;
+ vita_device_t *vita;
+ typedef BroadcastSignal BS;
-CmaClient::~CmaClient()
-{
- if(device) {
- close();
+ while(active) {
+ vita = VitaMTP_Get_First_USB_Vita();
+ if(vita || !active) {
+ break;
+ }
+ qDebug("No Vita detected via USB, attempt %i", ++num_tries);
+ vita = VitaMTP_Get_First_Wireless_Vita(&BS::info, 0, 2, BS::deviceRegistered, BS::generatePin);
+ if(vita || !active) {
+ break;
+ }
+ qDebug("No Vita detected via wireless, attempt %i", ++num_tries);
}
-}
-void CmaClient::close()
-{
- VitaMTP_SendHostStatus(device, VITA_HOST_STATUS_EndConnection);
- VitaMTP_Release_Device(device);
- device = NULL;
+ return vita;
}
void CmaClient::process()
{
- qDebug("Vita connected: id %s", VitaMTP_Get_Identification(device));
+ qDebug() << "Starting CmaClient:" << QThread::currentThreadId();
- DeviceCapability *vita_info = new DeviceCapability();
+ connect(&broadcast, SIGNAL(receivedPin(int)), this, SIGNAL(receivedPin(int)));
- if(!vita_info->exchangeInfo(device)) {
- qCritical("Error while exchanging info with the vita");
- close();
+ active = true;
+
+ while(active) {
+
+ if((device = getDeviceConnection()) == NULL) {
+ break;
+ }
+ broadcast.setUnavailable();
+ qDebug("Vita connected: id %s", VitaMTP_Get_Identification(device));
+ DeviceCapability *vita_info = new DeviceCapability();
+
+ if(!vita_info->exchangeInfo(device)) {
+ qCritical("Error while exchanging info with the vita");
+ close();
+ broadcast.setAvailable();
+ continue;
+ }
+
+ // Conection successful, inform the user
+ emit deviceConnected(QString(tr("Connected to ")) + vita_info->getOnlineId());
+ connected = true;
+ enterEventLoop();
+ broadcast.setAvailable();
}
-
- // Conection successful, inform the user
- emit deviceConnected(QString(tr("Connected to ")) + vita_info->getOnlineId());
- connected = true;
- enterEventLoop();
+ emit finished();
}
-
void CmaClient::enterEventLoop()
{
vita_event_t event;
- qDebug() << "From listener:"<< QThread::currentThreadId();
+ qDebug("Starting event loop");
while(connected) {
if(VitaMTP_Read_Event(device, &event) < 0) {
@@ -134,9 +176,10 @@ void CmaClient::enterEventLoop()
default:
vitaEventUnimplementated(&event, event.Param1);
}
+ qDebug("Ended event, code: 0x%x, id: %d", event.Code, event.Param1);
}
- qDebug() << "Finished event thread for:" << QThread::currentThreadId();
- emit finished();
+ qDebug("Finished event thread");
+ emit deviceDisconnected();
}
quint16 CmaClient::processAllObjects(CMAObject *parent, quint32 handle)
@@ -154,12 +197,12 @@ quint16 CmaClient::processAllObjects(CMAObject *parent, quint32 handle)
return PTP_RC_VITA_Invalid_Data;
}
- CMAObject *object = db->pathToObject(remote_meta.name, parent->metadata.ohfi);
+ CMAObject *object = db.pathToObject(remote_meta.name, parent->metadata.ohfi);
if(object) {
qDebug("Deleting %s", object->path.toStdString().c_str());
removeRecursively(object->path);
- db->remove(object);
+ db.remove(object);
}
QDir dir(parent->path);
@@ -188,7 +231,7 @@ quint16 CmaClient::processAllObjects(CMAObject *parent, quint32 handle)
object = new CMAObject(parent);
object->initObject(info);
object->metadata.handle = remote_meta.handle;
- db->append(parent->metadata.ohfi, object);
+ db.append(parent->metadata.ohfi, object);
free(remote_meta.name);
qDebug("Added object %s with OHFI %i to database", object->metadata.path, object->metadata.ohfi);
@@ -199,7 +242,7 @@ quint16 CmaClient::processAllObjects(CMAObject *parent, quint32 handle)
if(ret != PTP_RC_OK) {
qDebug("Deleteting object with OHFI %d", object->metadata.ohfi);
- db->remove(object);
+ db.remove(object);
free(data.fileData);
return ret;
}
@@ -221,9 +264,9 @@ void CmaClient::vitaEventGetTreatObject(vita_event_t *event, int eventId)
return;
}
- QMutexLocker locker(&db->mutex);
+ QMutexLocker locker(&db.mutex);
- CMAObject *parent = db->ohfiToObject(treatObject.ohfiParent);
+ CMAObject *parent = db.ohfiToObject(treatObject.ohfiParent);
if(parent == NULL) {
qWarning("Cannot find parent OHFI %d", treatObject.ohfiParent);
@@ -244,14 +287,14 @@ void CmaClient::vitaEventSendCopyConfirmationInfo(vita_event_t *event, int event
return;
}
- QMutexLocker locker(&db->mutex);
+ QMutexLocker locker(&db.mutex);
quint64 size = 0;
for(quint32 i = 0; i < info->count; i++) {
CMAObject *object;
- if((object = db->ohfiToObject(info->ohfi[i])) == NULL) {
+ if((object = db.ohfiToObject(info->ohfi[i])) == NULL) {
qWarning("Cannot find OHFI %d", info->ohfi[i]);
free(info);
return;
@@ -279,9 +322,9 @@ void CmaClient::vitaEventSendObjectMetadataItems(vita_event_t *event, int eventI
return;
}
- QMutexLocker locker(&db->mutex);
+ QMutexLocker locker(&db.mutex);
- CMAObject *object = db->ohfiToObject(ohfi);
+ CMAObject *object = db.ohfiToObject(ohfi);
if(object == NULL) {
qWarning("Cannot find OHFI %d in database", ohfi);
@@ -324,10 +367,10 @@ void CmaClient::vitaEventSendNumOfObject(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
- QMutexLocker locker(&db->mutex);
+ QMutexLocker locker(&db.mutex);
uint ohfi = event->Param2;
- int items = db->filterObjects(ohfi, NULL);
+ int items = db.filterObjects(ohfi, NULL);
if(VitaMTP_SendNumOfObject(device, eventId, items) != PTP_RC_OK) {
qWarning("Error occured receiving object count for OHFI parent %d", ohfi);
@@ -347,10 +390,10 @@ void CmaClient::vitaEventSendObjectMetadata(vita_event_t *event, int eventId)
qWarning("GetBrowseInfo failed");
return;
}
- QMutexLocker locker(&db->mutex);
+ QMutexLocker locker(&db.mutex);
metadata_t *meta;
- int count = db->filterObjects(browse.ohfiParent, &meta); // if meta is null, will return empty XML
+ int count = db.filterObjects(browse.ohfiParent, &meta); // if meta is null, will return empty XML
qDebug("Sending %i metadata filtered objects for OHFI %d", count, browse.ohfiParent);
if(VitaMTP_SendObjectMetadata(device, eventId, meta) != PTP_RC_OK) { // send all objects with OHFI parent
@@ -366,10 +409,12 @@ void CmaClient::vitaEventSendObject(vita_event_t *event, int eventId)
int ohfi = event->Param2;
- QMutexLocker locker(&db->mutex);
+ QMutexLocker locker(&db.mutex);
+
+ qDebug("Searching object with OHFI %d", ohfi);
Database::find_data iters;
- if(!db->find(ohfi, iters)) {
+ if(!db.find(ohfi, iters)) {
qWarning("Failed to find OHFI %d", ohfi);
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI);
return;
@@ -379,6 +424,7 @@ void CmaClient::vitaEventSendObject(vita_event_t *event, int eventId)
CMAObject *object = *iters.it;
CMAObject *start = object;
uint parentHandle = event->Param3;
+ bool send_folder = object->metadata.dataType & Folder;
uint handle;
do {
@@ -415,12 +461,22 @@ void CmaClient::vitaEventSendObject(vita_event_t *event, int eventId)
}
object->metadata.handle = handle;
- file.unmap(data);
- object = *iters.it++;
+
+ if(object->metadata.dataType & File) {
+ file.unmap(data);
+ }
+
+ // break early if only a file needs to be sent
+ if(!send_folder) {
+ break;
+ }
+
+ object = *++iters.it;
} while(iters.it != iters.end && object->metadata.ohfiParent >= OHFI_OFFSET); // get everything under this "folder"
VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, handle);
+
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data); // TODO: Send thumbnail
}
@@ -488,9 +544,9 @@ void CmaClient::vitaEventSendObjectStatus(vita_event_t *event, int eventId)
return;
}
- QMutexLocker locker(&db->mutex);
+ QMutexLocker locker(&db.mutex);
- CMAObject *object = db->pathToObject(objectstatus.title, objectstatus.ohfiRoot);
+ CMAObject *object = db.pathToObject(objectstatus.title, objectstatus.ohfiRoot);
if(object == NULL) { // not in database, don't return metadata
qDebug("Object %s not in database (OHFI: %i). Sending OK response for non-existence", objectstatus.title, objectstatus.ohfiRoot);
@@ -514,10 +570,10 @@ void CmaClient::vitaEventSendObjectThumb(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
- QMutexLocker locker(&db->mutex);
+ QMutexLocker locker(&db.mutex);
int ohfi = event->Param2;
- CMAObject *object = db->ohfiToObject(ohfi);
+ CMAObject *object = db.ohfiToObject(ohfi);
if(object == NULL) {
qWarning("Cannot find OHFI %d in database.", ohfi);
@@ -525,33 +581,12 @@ void CmaClient::vitaEventSendObjectThumb(vita_event_t *event, int eventId)
return;
}
- QByteArray data;
+ QByteArray data = getThumbnail(object->path, object->metadata.dataType, &g_thumbmeta);
- if(MASK_SET(object->metadata.dataType, SaveData)) {
- QString thumbpath = QDir(object->path).absoluteFilePath("ICON0.PNG");
- qDebug("Sending savedata thumbnail from %s", thumbpath.toStdString().c_str());
-
- QFile file(thumbpath);
- if(!file.open(QIODevice::ReadOnly)) {
- qWarning("Cannot find thumbnail %s", thumbpath.toStdString().c_str());
- VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data);
- return;
- }
- data = file.readAll();
-
- } else {
- QImage img;
- if(!MASK_SET(object->metadata.dataType, Photo) || !img.load(object->path)) {
- qWarning("Thumbnail sending for the file %s is not supported", object->metadata.path);
- VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data);
- return;
- }
- qDebug("Creating thumbnail of %s", object->metadata.name);
-
- QBuffer buffer(&data);
- buffer.open(QIODevice::WriteOnly);
- QImage result = img.scaled(256, 256, Qt::KeepAspectRatio, Qt::FastTransformation);
- result.save(&buffer, "JPEG");
+ if(data.size() == 0) {
+ qWarning("Cannot find/read thumbnail for %s", object->path.toStdString().c_str());
+ VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data);
+ return;
}
// workaround for the vitamtp locale bug
@@ -573,10 +608,10 @@ void CmaClient::vitaEventDeleteObject(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
- QMutexLocker locker(&db->mutex);
+ QMutexLocker locker(&db.mutex);
int ohfi = event->Param2;
- CMAObject *object = db->ohfiToObject(ohfi);
+ CMAObject *object = db.ohfiToObject(ohfi);
if(object == NULL) {
qWarning("OHFI %d not found", ohfi);
@@ -586,7 +621,7 @@ void CmaClient::vitaEventDeleteObject(vita_event_t *event, int eventId)
qDebug("Deleting %s, OHFI: %i", object->metadata.path, object->metadata.ohfi);
removeRecursively(object->path);
- db->remove(object);
+ db.remove(object);
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
}
@@ -603,10 +638,12 @@ void CmaClient::vitaEventGetSettingInfo(vita_event_t *event, int eventId)
qDebug("Current account id: %s", settingsinfo->current_account.accountId);
- db->setUUID(settingsinfo->current_account.accountId);
- // set the database to be updated ASAP
- emit refreshDatabase();
+ if(QSettings().value("lastAccountId").toString() != settingsinfo->current_account.accountId) {
+ db.setUUID(settingsinfo->current_account.accountId);
+ // set the database to be updated ASAP
+ emit refreshDatabase();
+ }
// free all the information
VitaMTP_Data_Free_Settings(settingsinfo);
@@ -660,9 +697,9 @@ void CmaClient::vitaEventSendPartOfObject(vita_event_t *event, int eventId)
return;
}
- QMutexLocker locker(&db->mutex);
+ QMutexLocker locker(&db.mutex);
- CMAObject *object = db->ohfiToObject(part_init.ohfi);
+ CMAObject *object = db.ohfiToObject(part_init.ohfi);
if(object == NULL) {
qWarning("Cannot find object for OHFI %d", part_init.ohfi);
@@ -700,9 +737,9 @@ void CmaClient::vitaEventOperateObject(vita_event_t *event, int eventId)
return;
}
- QMutexLocker locker(&db->mutex);
+ QMutexLocker locker(&db.mutex);
- CMAObject *root = db->ohfiToObject(operateobject.ohfi);
+ CMAObject *root = db.ohfiToObject(operateobject.ohfi);
// end for renaming only
if(root == NULL) {
@@ -721,7 +758,7 @@ void CmaClient::vitaEventOperateObject(vita_event_t *event, int eventId)
} else {
CMAObject *newobj = new CMAObject(root);
newobj->initObject(QFileInfo(dir, operateobject.title));
- db->append(operateobject.ohfi, newobj);
+ db.append(operateobject.ohfi, newobj);
qDebug("Created folder %s with OHFI %d under parent %s", newobj->metadata.path, newobj->metadata.ohfi, root->metadata.path);
VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, newobj->metadata.ohfi);
}
@@ -737,7 +774,7 @@ void CmaClient::vitaEventOperateObject(vita_event_t *event, int eventId)
} else {
CMAObject *newobj = new CMAObject(root);
newobj->initObject(file);
- db->append(root->metadata.ohfi, newobj);
+ db.append(root->metadata.ohfi, newobj);
qDebug("Created file %s with OHFI %d under parent %s", newobj->metadata.path, newobj->metadata.ohfi, root->metadata.path);
VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, newobj->metadata.ohfi);
}
@@ -752,7 +789,7 @@ void CmaClient::vitaEventOperateObject(vita_event_t *event, int eventId)
//rename the current object
root->rename(operateobject.title);
Database::find_data iters;
- db->find(root->metadata.ohfi, iters);
+ db.find(root->metadata.ohfi, iters);
// rename the rest of the list only if has the renamed parent in some part of the chain
while(iters.it != iters.end) {
@@ -796,8 +833,8 @@ void CmaClient::vitaEventGetPartOfObject(vita_event_t *event, int eventId)
return;
}
- QMutexLocker locker(&db->mutex);
- CMAObject *object = db->ohfiToObject(part_init.ohfi);
+ QMutexLocker locker(&db.mutex);
+ CMAObject *object = db.ohfiToObject(part_init.ohfi);
if(object == NULL) {
qWarning("Cannot find OHFI %d", part_init.ohfi);
@@ -828,10 +865,10 @@ void CmaClient::vitaEventSendStorageSize(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
- QMutexLocker locker(&db->mutex);
+ QMutexLocker locker(&db.mutex);
int ohfi = event->Param2;
- CMAObject *object = db->ohfiToObject(ohfi);
+ CMAObject *object = db.ohfiToObject(ohfi);
if(object == NULL) {
qWarning("Error: Cannot find OHFI %d", ohfi);
@@ -882,9 +919,9 @@ void CmaClient::vitaEventCheckExistance(vita_event_t *event, int eventId)
return;
}
- QMutexLocker locker(&db->mutex);
+ QMutexLocker locker(&db.mutex);
- CMAObject *object = db->pathToObject(existance.name, 0);
+ CMAObject *object = db.pathToObject(existance.name, 0);
if(object == NULL) {
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Different_Object);
@@ -894,3 +931,23 @@ void CmaClient::vitaEventCheckExistance(vita_event_t *event, int eventId)
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
}
+
+void CmaClient::close()
+{
+ VitaMTP_SendHostStatus(device, VITA_HOST_STATUS_EndConnection);
+ VitaMTP_Release_Device(device);
+}
+
+void CmaClient::stop()
+{
+ active = false;
+ connected = false;
+ waitCondition.wakeAll();
+}
+
+CmaClient::~CmaClient()
+{
+ if(device) {
+ close();
+ }
+}
diff --git a/cmaclient.h b/cmaclient.h
index af40560..5b6a5c2 100644
--- a/cmaclient.h
+++ b/cmaclient.h
@@ -1,12 +1,33 @@
+/*
+ * QCMA: Cross-platform content manager assistant for the PS Vita
+ *
+ * Copyright (C) 2013 Codestation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
#ifndef CMACLIENT_H
#define CMACLIENT_H
#include "baseworker.h"
+#include "cmabroadcast.h"
#include "cmaobject.h"
#include "database.h"
#include
#include
+#include
extern "C" {
#include
@@ -17,11 +38,13 @@ class CmaClient : public BaseWorker
Q_OBJECT
public:
explicit CmaClient(QObject *parent = 0);
- explicit CmaClient(Database *database, vita_device_t *device, QObject *parent = 0);
~CmaClient();
+ Database db;
+
private:
void enterEventLoop();
+ vita_device_t *getDeviceConnection();
uint16_t processAllObjects(CMAObject *parent, uint32_t handle);
void vitaEventSendObject(vita_event_t *event, int eventId);
@@ -46,18 +69,23 @@ private:
void vitaEventSendNPAccountInfo(vita_event_t *event, int eventId);
void vitaEventRequestTerminate(vita_event_t *event, int eventId);
- Database *db;
+ QWaitCondition waitCondition;
+ CmaBroadcast broadcast;
vita_device_t *device;
+ volatile bool active;
volatile bool connected;
- static const metadata_t g_thumbmeta;
+ static metadata_t g_thumbmeta;
signals:
+ void receivedPin(int);
+ void deviceDetected();
void deviceConnected(QString);
+ void deviceDisconnected();
void refreshDatabase();
- void terminate();
public slots:
void close();
+ void stop();
private slots:
void process();
diff --git a/cmarootobject.cpp b/cmarootobject.cpp
index 999f8b7..afbac7b 100644
--- a/cmarootobject.cpp
+++ b/cmarootobject.cpp
@@ -38,9 +38,12 @@ void CMARootObject::initObject(const QString &path)
metadata.dataType = Music;
this->path = path;
num_filters = 1;
- filters = new metadata_t[1];
- //createFilter(&filters[0], "Folders", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_PLAYLISTS);
- createFilter(&filters[0], "All", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_SONGS);
+ filters = new metadata_t[2];
+ //createFilter(&filters[0], "Artists", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_ARTISTS);
+ createFilter(&filters[0], "Albums", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_ALBUMS);
+ createFilter(&filters[1], "All", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_SONGS);
+ //createFilter(&filters[3], "Genres", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_GENRES);
+ //createFilter(&filters[4], "Playlists", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_PLAYLISTS);
break;
case VITA_OHFI_PHOTO:
@@ -119,6 +122,7 @@ void CMARootObject::createFilter(metadata_t *filter, const char *name, int type)
filter->size = 0;
filter->dataType = static_cast(Folder | Special);
filter->next_metadata = NULL;
+ qDebug("Added filter %s to database with OHFI %d (%s)", name, filter->ohfi, metadata.name);
}
int CMARootObject::getFilters(metadata_t **p_head)
diff --git a/cmaserver.cpp b/cmaserver.cpp
deleted file mode 100644
index 2969c53..0000000
--- a/cmaserver.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-#include "cmaserver.h"
-#include "wirelessworker.h"
-
-#include
-#include
-#include
-#include
-
-CmaServer::CmaServer(QObject *parent) :
- QObject(parent), num_retries(0)
-{
- strcpy(hostname, QHostInfo::localHostName().toStdString().c_str());
- BroadcastSignal::info.name = hostname;
-}
-
-void CmaServer::listen()
-{
- QThread *thread = new QThread();
- if(QSettings().value("wireless", false).toBool()) {
- connect(&timer, SIGNAL(timeout()), this, SLOT(connectWireless()));
- broadcast.start();
- timer.setSingleShot(true);
- } else {
- timer.setSingleShot(false);
- connect(&timer, SIGNAL(timeout()), this, SLOT(connectUsb()));
- }
- moveToThread(thread);
- connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
- timer.start(2000);
- thread->start();
-}
-
-void CmaServer::connectUsb()
-{
- qDebug() << "From connectUsb: "<< QThread::currentThreadId();
-
- vita_device_t *vita = VitaMTP_Get_First_USB_Vita();
- if(vita) {
- qDebug("Detected PS Vita via USB");
- timer.stop();
- emit newConnection(vita);
- } else {
- qDebug("No PS Vita found. Attempt %d", ++num_retries);
- }
-}
-
-void CmaServer::connectWireless()
-{
- typedef BroadcastSignal BS;
-
- qDebug() << "From connectWireless: "<< QThread::currentThreadId();
-
- vita_device_t *vita = VitaMTP_Get_First_Wireless_Vita(&BS::info, 0, 0, BS::deviceRegistered, BS::generatePin);
- if(vita) {
- qDebug("Detected PS Vita in wireless mode");
- emit newConnection(vita);
- } else {
- qDebug("PS Vita couldn't be detected. Attempt %d", ++num_retries);
- }
-}
-
-void CmaServer::continueProcess()
-{
- qDebug("Restarting CmaServer thread");
- num_retries = 0;
- timer.start();
-}
-
-void CmaServer::stopProcess()
-{
- timer.stop();
-}
diff --git a/cmaserver.h b/cmaserver.h
deleted file mode 100644
index 95855eb..0000000
--- a/cmaserver.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef CMASERVER_H
-#define CMASERVER_H
-
-#include "wirelessworker.h"
-
-extern "C" {
-#include
-}
-
-#include
-
-#include
-#include
-#include
-#include
-
-class CmaServer : public QObject
-{
- Q_OBJECT
-public:
- explicit CmaServer(QObject *parent = 0);
- void listen();
- void close();
-
- int num_retries;
- QTimer timer;
- QThread *thread;
- char hostname[256];
- BroadcastSignal broadcast;
-
-signals:
- void newConnection(vita_device_t *);
- void createdPin(int);
- void finished();
-
-public slots:
- void continueProcess();
- void stopProcess();
-
-private slots:
- void connectWireless();
- void connectUsb();
-};
-
-#endif // CMASERVER_H
diff --git a/database.cpp b/database.cpp
index 598c75d..d38ef8f 100644
--- a/database.cpp
+++ b/database.cpp
@@ -27,9 +27,14 @@
#define OHFI_OFFSET 1000
+const QStringList Database::image_types = QStringList() << "jpg" << "jpeg" << "png" << "tif" << "tiff" << "bmp" << "gif" << "mpo";
+const QStringList Database::audio_types = QStringList() << "mp3" << "mp4" << "wav";
+const QStringList Database::video_types = QStringList() << "mp4";
+
Database::Database(QObject *parent) :
QObject(parent), mutex(QMutex::Recursive)
{
+ CMARootObject::uuid = QSettings().value("lastAccountId", "ffffffffffffffff").toString();
}
Database::~Database()
@@ -40,6 +45,7 @@ Database::~Database()
void Database::setUUID(const QString uuid)
{
CMARootObject::uuid = uuid;
+ QSettings().setValue("lastAccountId", uuid);
}
int Database::create()
@@ -75,12 +81,13 @@ int Database::create()
case VITA_OHFI_PSPSAVE:
case VITA_OHFI_PSXAPP:
case VITA_OHFI_PSMAPP:
+
obj->initObject(settings.value("appsPath").toString());
}
root_list list;
list << obj;
- total_objects += scanRootDirectory(list);
+ total_objects += recursiveScanRootDirectory(list, obj, ohfi_array[i]);
object_list[ohfi_array[i]] = list;
}
return total_objects;
@@ -95,7 +102,7 @@ CMAObject *Database::getParent(CMAObject *last_dir, const QString ¤t_path)
return last_dir;
}
-int Database::scanRootDirectory(root_list &list)
+int Database::scanRootDirectory(root_list &list, int ohfi_type)
{
int total_objects = 0;
CMAObject *last_dir = list.first();
@@ -105,8 +112,16 @@ int Database::scanRootDirectory(root_list &list)
while(it.hasNext()) {
it.next();
- CMAObject *obj = new CMAObject(getParent(last_dir, it.fileInfo().path()));
- obj->initObject(it.fileInfo());
+ QFileInfo info = it.fileInfo();
+
+ if(info.isFile() && !checkFileType(info.absoluteFilePath(), ohfi_type)) {
+ //qDebug("Excluding %s from database", info.absoluteFilePath().toStdString().c_str());
+ continue;
+ }
+
+ CMAObject *obj = new CMAObject(getParent(last_dir, info.path()));
+ obj->initObject(info);
+ qDebug("Added %s to database with OHFI %d", obj->metadata.name, obj->metadata.ohfi);
list << obj;
if(obj->metadata.dataType & Folder) {
@@ -118,6 +133,33 @@ int Database::scanRootDirectory(root_list &list)
return total_objects;
}
+int Database::recursiveScanRootDirectory(root_list &list, CMAObject *parent, int ohfi_type)
+{
+ int total_objects = 0;
+
+ QDir dir(parent->path);
+ dir.setSorting(QDir::Name | QDir::DirsFirst);
+ QFileInfoList qsl = dir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot);
+
+ foreach(const QFileInfo &info, qsl) {
+ if(info.isFile() && !checkFileType(info.absoluteFilePath(), ohfi_type)) {
+ //qDebug("Excluding %s from database", info.absoluteFilePath().toStdString().c_str());>
+ } else {
+ CMAObject *obj = new CMAObject(parent);
+ obj->initObject(info);
+ qDebug("Added %s to database with OHFI %d", obj->metadata.name, obj->metadata.ohfi);
+ list << obj;
+ if(info.isDir()) {
+ total_objects += recursiveScanRootDirectory(list, obj, ohfi_type);
+ } else {
+ total_objects++;
+ }
+ }
+ }
+
+ return total_objects;
+}
+
void Database::destroy()
{
QMutexLocker locker(&mutex);
@@ -282,6 +324,14 @@ int Database::acceptFilteredObject(const CMAObject *parent, const CMAObject *cur
return result;
}
+void Database::dumpMetadataList(const metadata_t *p_head)
+{
+ while(p_head) {
+ qDebug("Metadata: %s with OHFI %d", p_head->name, p_head->ohfi);
+ p_head = p_head->next_metadata;
+ }
+}
+
int Database::filterObjects(int ohfiParent, metadata_t **p_head)
{
QMutexLocker locker(&mutex);
@@ -330,5 +380,38 @@ int Database::filterObjects(int ohfiParent, metadata_t **p_head)
*p_head = temp.next_metadata;
}
+ if(p_head) {
+ dumpMetadataList(*p_head);
+ }
return numObjects;
}
+
+bool Database::checkFileType(const QString path, int ohfi_root)
+{
+ switch(ohfi_root) {
+ case VITA_OHFI_MUSIC:
+ foreach(const QString &ext, audio_types) {
+ if(path.endsWith(ext, Qt::CaseInsensitive)) {
+ return true;
+ }
+ }
+ break;
+ case VITA_OHFI_PHOTO:
+ foreach(const QString &ext, image_types) {
+ if(path.endsWith(ext, Qt::CaseInsensitive)) {
+ return true;
+ }
+ }
+ break;
+ case VITA_OHFI_VIDEO:
+ foreach(const QString &ext, video_types) {
+ if(path.endsWith(ext, Qt::CaseInsensitive)) {
+ return true;
+ }
+ }
+ break;
+ default:
+ return true;
+ }
+ return false;
+}
diff --git a/database.h b/database.h
index 40c6744..cb47ff8 100644
--- a/database.h
+++ b/database.h
@@ -62,13 +62,20 @@ private:
typedef QList root_list;
typedef QMap map_list;
- int scanRootDirectory(root_list &list);
+ static const QStringList audio_types;
+ static const QStringList image_types;
+ static const QStringList video_types;
+
+ int scanRootDirectory(root_list &list,int ohfi_type);
+ int recursiveScanRootDirectory(root_list &list, CMAObject *parent, int ohfi_type);
bool hasFilter(const CMARootObject *object,int ohfi);
bool removeInternal(root_list &list, const CMAObject *obj);
bool findInternal(const root_list &list, int ohfi, find_data &data);
CMAObject *getParent(CMAObject *last_dir, const QString ¤t_path);
CMAObject *pathToObjectInternal(const root_list &list, const char *path);
static bool lessThanComparator(const CMAObject *a, const CMAObject *b);
+ bool checkFileType(const QString path, int ohfi_root);
+ void dumpMetadataList(const metadata_t *p_head);
map_list object_list;
diff --git a/main.cpp b/main.cpp
index 3e48253..4a4f1ed 100644
--- a/main.cpp
+++ b/main.cpp
@@ -43,8 +43,6 @@ int main(int argc, char *argv[])
SingleApplication app(argc, argv);
-
-
if(!app.arguments().contains("--with-debug")) {
VitaMTP_Set_Logging(VitaMTP_NONE);
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
@@ -56,7 +54,7 @@ int main(int argc, char *argv[])
VitaMTP_Set_Logging(VitaMTP_VERBOSE);
}
- qDebug()<<"From main thread: "<
#include
#include
+#include
const QStringList MainWidget::path_list = QStringList() << "photoPath" << "musicPath" << "videoPath" << "appsPath" << "urlPath";
@@ -64,34 +65,22 @@ void MainWidget::dialogResult(int result)
void MainWidget::startServer()
{
- connect(&server, SIGNAL(newConnection(vita_device_t *)), this, SLOT(startClient(vita_device_t*)));
- connect(&server, SIGNAL(createdPin(int)), this, SLOT(showPin(int)));
- //connect(&server, SIGNAL(finished()), qApp, SLOT(quit()));
+ qDebug("Starting cma event loop");
+ clientLoop.start();
+}
- qDebug("Starting cma server");
- server.listen();
+void MainWidget::stopServer()
+{
+ clientLoop.stop();
}
void MainWidget::refreshDatabase()
{
- db.mutex.lock();
- db.destroy();
- int count = db.create();
- qDebug("Indexed %i elements in the database", count);
- db.mutex.unlock();
-}
-
-void MainWidget::startClient(vita_device_t *device)
-{
- server.stopProcess();
- qDebug() << "From startClient: "<< QThread::currentThreadId();
- qDebug("Starting new client connection");
- CmaClient *client = new CmaClient(&db, device);
- connect(client, SIGNAL(deviceConnected(QString)), this, SLOT(receiveMessage(QString)));
- connect(client, SIGNAL(deviceConnected(QString)), this, SLOT(setTrayTooltip(QString)));
- connect(client, SIGNAL(refreshDatabase()), this, SLOT(refreshDatabase()));
- connect(client, SIGNAL(finished()), &server, SLOT(continueProcess()));
- client->start();
+ clientLoop.db.mutex.lock();
+ clientLoop.db.destroy();
+ int count = clientLoop.db.create();
+ qDebug("Added %i entries to the database", count);
+ clientLoop.db.mutex.unlock();
}
void MainWidget::deviceDisconnect()
@@ -103,6 +92,12 @@ void MainWidget::deviceDisconnect()
void MainWidget::connectSignals()
{
connect(&dialog, SIGNAL(finished(int)), this, SLOT(dialogResult(int)));
+ connect(&clientLoop, SIGNAL(receivedPin(int)), this, SLOT(showPin(int)));
+ connect(&clientLoop, SIGNAL(deviceConnected(QString)), this, SLOT(receiveMessage(QString)));
+ connect(&clientLoop, SIGNAL(deviceConnected(QString)), this, SLOT(setTrayTooltip(QString)));
+ connect(&clientLoop, SIGNAL(deviceDisconnected()), this, SLOT(deviceDisconnect()));
+ connect(&clientLoop, SIGNAL(refreshDatabase()), this, SLOT(refreshDatabase()));
+ connect(&clientLoop, SIGNAL(finished()), qApp, SLOT(quit()));
}
void MainWidget::showPin(int pin)
@@ -115,6 +110,7 @@ void MainWidget::prepareApplication()
connectSignals();
createTrayIcon();
checkSettings();
+ refreshDatabase();
}
void MainWidget::setTrayTooltip(QString message)
@@ -153,7 +149,7 @@ void MainWidget::createTrayIcon()
connect(options, SIGNAL(triggered()), &dialog, SLOT(open()));
//connect(reload, SIGNAL(triggered()), &CmaWorker, SLOT(allowRefresh()), Qt::DirectConnection);
- connect(quit, SIGNAL(triggered()), qApp, SLOT(quit()));
+ connect(quit, SIGNAL(triggered()), this, SLOT(stopServer()));
connect(wireless, SIGNAL(triggered()), this, SLOT(toggleWireless()));
QMenu *trayIconMenu = new QMenu(this);
diff --git a/mainwidget.h b/mainwidget.h
index 3184613..30ad0af 100644
--- a/mainwidget.h
+++ b/mainwidget.h
@@ -21,8 +21,7 @@
#define MAINWIDGET_H
#include "configwidget.h"
-#include "cmaserver.h"
-#include "database.h"
+#include "cmaclient.h"
#include
#include
@@ -56,8 +55,7 @@ private:
QAction *reload;
QAction *options;
QAction *wireless;
- Database db;
- CmaServer server;
+ CmaClient clientLoop;
const static QStringList path_list;
private slots:
@@ -67,9 +65,9 @@ private slots:
void setTrayTooltip(QString message);
void toggleWireless();
void showPin(int pin);
- void startClient(vita_device_t *device);
void refreshDatabase();
void startServer();
+ void stopServer();
};
#endif // MAINWIDGET_H
diff --git a/qcma.pro b/qcma.pro
index 09522fb..74f3587 100644
--- a/qcma.pro
+++ b/qcma.pro
@@ -25,8 +25,8 @@ SOURCES += main.cpp \
singleapplication.cpp \
baseworker.cpp \
sforeader.cpp \
- cmaserver.cpp \
- cmaclient.cpp
+ cmaclient.cpp \
+ cmabroadcast.cpp
HEADERS += \
wirelessworker.h \
@@ -40,11 +40,11 @@ HEADERS += \
singleapplication.h \
baseworker.h \
sforeader.h \
- cmaserver.h \
- cmaclient.h
+ cmaclient.h \
+ cmabroadcast.h
CONFIG += link_pkgconfig
-PKGCONFIG += libvitamtp libmediainfo
+PKGCONFIG += libmediainfo
QMAKE_CXXFLAGS += -Wno-write-strings -Wall
@@ -57,3 +57,11 @@ OTHER_FILES += \
FORMS += \
configwidget.ui
+
+win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../../usr/lib/release/ -lvitamtp
+else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../../usr/lib/debug/ -lvitamtp
+else:unix: LIBS += $$PWD/../../../../usr/lib/libvitamtp.a -lusb-1.0 -lxml2
+
+INCLUDEPATH += $$PWD/../../../../usr/include
+DEPENDPATH += $$PWD/../../../../usr/include
+
diff --git a/utils.cpp b/utils.cpp
index 1cd9559..418425b 100644
--- a/utils.cpp
+++ b/utils.cpp
@@ -19,19 +19,20 @@
#include "utils.h"
+#include
+#include
#include
#include
-extern "C" {
-#include
-}
-
#ifdef Q_OS_WIN32
#include
#else
#include
#endif
+#include
+#include
+
bool getDiskSpace(const QString &dir, quint64 *free, quint64 *total)
{
#ifdef Q_OS_WIN32
@@ -79,3 +80,83 @@ bool removeRecursively(const QString &dirName)
return result;
#endif
}
+
+QByteArray findFolderAlbumArt(const QString path, metadata_t *metadata)
+{
+ QByteArray data;
+ QDir folder(path);
+
+ QStringList files = folder.entryList(QDir::Files | QDir::Readable);
+ const QStringList cover_list = QStringList() << "album" << "cover" << "front";
+ const QStringList ext_list = QStringList() << "jpg" << "jpeg" << "png" << "gif";
+
+ foreach(const QString &file, files) {
+ foreach(const QString &cover, cover_list) {
+ foreach(const QString &ext, ext_list) {
+ if(file.compare(QString("%1.%2").arg(cover, ext), Qt::CaseInsensitive) == 0) {
+ qDebug() << "Trying to load album art from" << folder.absoluteFilePath(file);
+ QImage img;
+ if(img.load(folder.absoluteFilePath(file))) {
+ QBuffer buffer(&data);
+ buffer.open(QIODevice::WriteOnly);
+ QImage result = img.scaled(256, 250, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ result.save(&buffer, "JPEG");
+ metadata->data.thumbnail.width = result.width();
+ metadata->data.thumbnail.height = result.height();
+ }
+ // only try with the first match
+ break;
+ }
+ }
+ }
+ }
+ return data;
+}
+
+QByteArray getThumbnail(const QString &path, DataType type, metadata_t *metadata)
+{
+ QByteArray data;
+
+ if(MASK_SET(type, SaveData)) {
+ QFile file(QDir(path).absoluteFilePath("ICON0.PNG"));
+
+ if(file.open(QIODevice::ReadOnly)) {
+ data = file.readAll();
+ }
+ } else if(MASK_SET(type, Photo)) {
+ QImage img;
+
+ if(img.load(path)) {
+ QBuffer buffer(&data);
+ buffer.open(QIODevice::WriteOnly);
+ QImage result = img.scaled(213, 120, Qt::KeepAspectRatio, Qt::FastTransformation);
+ result.save(&buffer, "JPEG");
+ metadata->data.thumbnail.width = result.width();
+ metadata->data.thumbnail.height = result.height();
+ }
+ } else if(MASK_SET(type, Music)) {
+ if(MASK_SET(type, Folder)) {
+ // TODO: try to load an album cover from one of the audio files.
+ data = findFolderAlbumArt(path, metadata);
+ } else {
+ MediaInfoLib::MediaInfo media;
+
+ if(media.Open(path.toStdWString())) {
+ QString base64 = QString::fromStdWString(media.Get(MediaInfoLib::Stream_General, 0, MediaInfoLib::General_Cover_Data));
+ QImage img;
+
+ if(base64.size() > 0 && img.loadFromData(QByteArray::fromBase64(base64.toUtf8()))) {
+ QBuffer buffer(&data);
+ buffer.open(QIODevice::WriteOnly);
+ // use smooth transformation for the ambum art since is important to display correctly
+ QImage result = img.scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ result.save(&buffer, "JPEG");
+ metadata->data.thumbnail.width = result.width();
+ metadata->data.thumbnail.height = result.height();
+ }
+ }
+ }
+ }
+ //TODO: implement thumbnails for videos
+ return data;
+}
diff --git a/utils.h b/utils.h
index 632d22e..3484eec 100644
--- a/utils.h
+++ b/utils.h
@@ -20,9 +20,14 @@
#ifndef UTILS_H
#define UTILS_H
+#include
#include
#include
+extern "C" {
+#include
+}
+
// Qt4 doesn't have public methods for Thread::*sleep
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
typedef QThread Sleeper;
@@ -38,5 +43,6 @@
bool removeRecursively(const QString &dirName);
bool getDiskSpace(const QString &dir, quint64 *free, quint64 *total);
+QByteArray getThumbnail(const QString &path, DataType type, metadata_t *metadata);
#endif // UTILS_H
diff --git a/wirelessworker.cpp b/wirelessworker.cpp
index 1550a48..759e283 100644
--- a/wirelessworker.cpp
+++ b/wirelessworker.cpp
@@ -35,6 +35,8 @@ BroadcastSignal::BroadcastSignal(QObject *parent) :
qsrand(QTime::currentTime().msec());
this_object = this;
started = false;
+ strcpy(hostname, QHostInfo::localHostName().toStdString().c_str());
+ BroadcastSignal::info.name = hostname;
}
BroadcastSignal::~BroadcastSignal()
@@ -54,7 +56,7 @@ int BroadcastSignal::generatePin(wireless_vita_info_t *info, int *p_err)
int pin = qrand() % 100000000;
qDebug("Your registration PIN for %s is: %08d", info->name, pin);
*p_err = 0;
- emit this_object->createdPin(pin);
+ emit this_object->receivedPin(pin);
return pin;
}
diff --git a/wirelessworker.h b/wirelessworker.h
index 82c602c..9d40c4c 100644
--- a/wirelessworker.h
+++ b/wirelessworker.h
@@ -44,12 +44,13 @@ public:
private:
- volatile bool started;
+ volatile bool started;
+ char hostname[256];
//used to emit a signal from a static method
static BroadcastSignal *this_object;
signals:
- void createdPin(int);
+ void receivedPin(int);
public slots:
void stopBroadcast();