Get a list of songs from a WMDM device

This commit is contained in:
David Sansome 2010-08-22 19:18:22 +00:00
parent bd4b6b2b50
commit 7821a48cb7
44 changed files with 818 additions and 50 deletions

View File

@ -540,8 +540,15 @@ endif(LIBMTP_FOUND)
# Windows media lister
IF(WIN32)
list(APPEND SOURCES devices/wmdmdevice.cpp)
list(APPEND SOURCES devices/wmdmlister.cpp)
list(APPEND SOURCES devices/wmdmloader.cpp)
list(APPEND SOURCES devices/wmdmthread.cpp)
list(APPEND HEADERS devices/wmdmdevice.h)
list(APPEND HEADERS devices/wmdmlister.h)
list(APPEND HEADERS devices/wmdmloader.h)
list(APPEND HEADERS devices/wmdmthread.h)
ENDIF(WIN32)
# Mac specific startup stuff

View File

@ -30,6 +30,7 @@
#endif
#ifdef Q_OS_WIN32
# include "wmdmlister.h"
# include "wmdmdevice.h"
#endif
#ifdef HAVE_LIBGPOD
# include "gpoddevice.h"
@ -183,6 +184,7 @@ DeviceManager::DeviceManager(BackgroundThread<Database>* database,
#endif
#ifdef Q_OS_WIN32
AddLister(new WmdmLister);
AddDeviceClass<WmdmDevice>();
#endif
#ifdef HAVE_IMOBILEDEVICE
AddLister(new iLister);

View File

@ -0,0 +1,92 @@
/* This file is part of Clementine.
Clementine 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.
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "devicemanager.h"
#include "wmdmdevice.h"
#include "wmdmloader.h"
#include "library/librarybackend.h"
#include "library/librarymodel.h"
#include <QThread>
WmdmDevice::WmdmDevice(const QUrl& url, DeviceLister* lister,
const QString& unique_id, DeviceManager* manager,
int database_id, bool first_time)
: ConnectedDevice(url, lister, unique_id, manager, database_id, first_time),
loader_thread_(new QThread(this)),
loader_(NULL)
{
}
WmdmDevice::~WmdmDevice() {
}
void WmdmDevice::Init() {
InitBackendDirectory("/", first_time_, false);
model_->Init();
loader_ = new WmdmLoader(manager_->task_manager(), backend_, shared_from_this());
loader_->moveToThread(loader_thread_);
connect(loader_, SIGNAL(Error(QString)), SIGNAL(Error(QString)));
connect(loader_, SIGNAL(TaskStarted(int)), SIGNAL(TaskStarted(int)));
connect(loader_, SIGNAL(LoadFinished()), SLOT(LoadFinished()));
connect(loader_thread_, SIGNAL(started()), loader_, SLOT(LoadDatabase()));
loader_thread_->start();
}
void WmdmDevice::LoadFinished() {
loader_->deleteLater();
loader_ = NULL;
}
void WmdmDevice::StartCopy() {
// Ensure only one "organise files" can be active at any one time
db_busy_.lock();
}
bool WmdmDevice::CopyToStorage(
const QString& source, const QString&, const Song& metadata,
bool, bool remove_original)
{
return false;
}
void WmdmDevice::FinishCopy(bool success) {
if (success) {
if (!songs_to_add_.isEmpty())
backend_->AddOrUpdateSongs(songs_to_add_);
if (!songs_to_remove_.isEmpty())
backend_->DeleteSongs(songs_to_remove_);
}
songs_to_add_.clear();
songs_to_remove_.clear();
db_busy_.unlock();
}
void WmdmDevice::StartDelete() {
StartCopy();
}
bool WmdmDevice::DeleteFromStorage(const Song& metadata) {
return false;
}
void WmdmDevice::FinishDelete(bool success) {
FinishCopy(success);
}

58
src/devices/wmdmdevice.h Normal file
View File

@ -0,0 +1,58 @@
/* This file is part of Clementine.
Clementine 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.
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WMDMDEVICE_H
#define WMDMDEVICE_H
#include "connecteddevice.h"
class WmdmLoader;
class WmdmDevice : public ConnectedDevice {
Q_OBJECT
public:
Q_INVOKABLE WmdmDevice(const QUrl& url, DeviceLister* lister,
const QString& unique_id, DeviceManager* manager,
int database_id, bool first_time);
~WmdmDevice();
static QStringList url_schemes() { return QStringList() << "wmdm"; }
void Init();
void StartCopy();
bool CopyToStorage(const QString& source, const QString& destination,
const Song& metadata, bool overwrite, bool remove_original);
void FinishCopy(bool success);
void StartDelete();
bool DeleteFromStorage(const Song& metadata);
void FinishDelete(bool success);
private slots:
void LoadFinished();
private:
QThread* loader_thread_;
WmdmLoader* loader_;
QMutex db_busy_;
SongList songs_to_add_;
SongList songs_to_remove_;
};
#endif // WMDMDEVICE_H

View File

@ -15,6 +15,7 @@
*/
#include "wmdmlister.h"
#include "wmdmthread.h"
#include <icomponentauthenticate.h>
#include <objbase.h>
@ -27,9 +28,6 @@
#include <QStringList>
#include <QtDebug>
BYTE abPVK[] = {0x00};
BYTE abCert[] = {0x00};
QString WmdmLister::CanonicalNameToId(const QString& canonical_name) {
return "wmdm/" + canonical_name;
}
@ -39,45 +37,20 @@ QString WmdmLister::DeviceInfo::unique_id() const {
}
WmdmLister::WmdmLister()
: device_manager_(NULL),
notification_cookie_(0)
: notification_cookie_(0)
{
}
WmdmLister::~WmdmLister() {
Q_ASSERT(!thread_);
}
void WmdmLister::Init() {
// Initialise COM
CoInitialize(0);
// Authenticate with WMDM
IComponentAuthenticate* auth;
if (CoCreateInstance(CLSID_MediaDevMgr, NULL, CLSCTX_ALL,
IID_IComponentAuthenticate, (void**) &auth)) {
qWarning() << "Error creating the IComponentAuthenticate interface";
return;
}
sac_ = CSecureChannelClient_New();
if (CSecureChannelClient_SetCertificate(
sac_, SAC_CERT_V1, abCert, sizeof(abCert), abPVK, sizeof(abPVK))) {
qWarning() << "Error setting SAC certificate";
return;
}
CSecureChannelClient_SetInterface(sac_, auth);
if (CSecureChannelClient_Authenticate(sac_, SAC_PROTOCOL_V1)) {
qWarning() << "Error authenticating with SAC";
return;
}
// Create the device manager
if (auth->QueryInterface(IID_IWMDeviceManager2, (void**)&device_manager_)) {
qWarning() << "Error creating WMDM device manager";
return;
}
thread_.reset(new WmdmThread);
// Register for notifications
IConnectionPointContainer* cp_container = NULL;
device_manager_->QueryInterface(IID_IConnectionPointContainer, (void**)&cp_container);
thread_->manager()->QueryInterface(IID_IConnectionPointContainer, (void**)&cp_container);
IConnectionPoint* cp = NULL;
cp_container->FindConnectionPoint(IID_IWMDMNotification, &cp);
@ -89,7 +62,7 @@ void WmdmLister::Init() {
// Fetch the initial list of devices
IWMDMEnumDevice* device_it = NULL;
if (device_manager_->EnumDevices2(&device_it)) {
if (thread_->manager()->EnumDevices2(&device_it)) {
qWarning() << "Error querying WMDM devices";
return;
}
@ -133,7 +106,7 @@ void WmdmLister::Init() {
void WmdmLister::ShutDown() {
// Unregister for notifications
IConnectionPointContainer* cp_container;
device_manager_->QueryInterface(IID_IConnectionPointContainer, (void**)&cp_container);
thread_->manager()->QueryInterface(IID_IConnectionPointContainer, (void**)&cp_container);
IConnectionPoint* cp;
cp_container->FindConnectionPoint(IID_IWMDMNotification, &cp);
@ -141,14 +114,7 @@ void WmdmLister::ShutDown() {
cp->Release();
cp_container->Release();
// Release the device manager
device_manager_->Release();
// SAC
CSecureChannelClient_Free(sac_);
// Uninitialise COM
CoUninitialize();
thread_.reset();
}
template <typename F>
@ -207,8 +173,8 @@ WmdmLister::DeviceInfo WmdmLister::ReadDeviceInfo(IWMDMDevice2* device) {
ret.free_bytes_ -= GetSpaceValue(boost::bind(&IWMDMStorageGlobals::GetTotalBad, globals, _1, _2));
globals->Release();
storage->Release();
}
storage->Release();
}
storage_it->Release();
}
@ -262,7 +228,11 @@ QString WmdmLister::MakeFriendlyName(const QString& id) {
}
QList<QUrl> WmdmLister::MakeDeviceUrls(const QString& id) {
return QList<QUrl>();
QUrl url;
url.setScheme("wmdm");
url.setPath(id);
return QList<QUrl>() << url;
}
void WmdmLister::UnmountDevice(const QString& id) {
@ -288,7 +258,7 @@ void WmdmLister::WMDMDeviceAdded(const QString& canonical_name) {
name[canonical_name.length()] = '\0';
IWMDMDevice* device = NULL;
if (device_manager_->GetDeviceFromCanonicalName(name.get(), &device)) {
if (thread_->manager()->GetDeviceFromCanonicalName(name.get(), &device)) {
qWarning() << "Error in GetDeviceFromCanonicalName for" << canonical_name;
return;
}
@ -321,6 +291,9 @@ void WmdmLister::WMDMDeviceRemoved(const QString& canonical_name) {
if (!devices_.contains(id))
return;
devices_[id].device_->Release();
devices_[id].storage_->Release();
devices_.remove(id);
}
@ -348,3 +321,7 @@ ULONG WmdmLister::Release() {
return 0;
}
QString WmdmLister::DeviceCanonicalName(const QString& id) {
return LockAndGetDeviceInfo(id, &DeviceInfo::canonical_name_);
}

View File

@ -23,16 +23,20 @@
#include <QMutex>
#include <QPixmap>
#include <boost/scoped_ptr.hpp>
#include <mswmdm.h>
#include <sac_shim.h>
#undef LoadIcon
class WmdmThread;
class WmdmLister : public DeviceLister, public IWMDMNotification {
Q_OBJECT
public:
WmdmLister();
~WmdmLister();
// DeviceLister
virtual void Init();
@ -55,6 +59,9 @@ public:
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
// Called by WmdmLister
QString DeviceCanonicalName(const QString& id);
public slots:
virtual void UpdateDeviceFreeSpace(const QString& id);
virtual void ShutDown();
@ -91,7 +98,8 @@ private:
void WMDMDeviceRemoved(const QString& canonical_name);
private:
IWMDeviceManager2* device_manager_;
boost::scoped_ptr<WmdmThread> thread_;
SacHandle sac_;
DWORD notification_cookie_;

348
src/devices/wmdmloader.cpp Normal file
View File

@ -0,0 +1,348 @@
/* This file is part of Clementine.
Clementine 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.
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "devicelister.h"
#include "wmdmdevice.h"
#include "wmdmlister.h"
#include "wmdmloader.h"
#include "wmdmthread.h"
#include "core/taskmanager.h"
#include "library/librarybackend.h"
#include <boost/scoped_array.hpp>
#include <cwchar>
#include <mswmdm.h>
#include <QUuid>
// Copied from the WMDM SDK 11, it doesn't seem to be included in SDK 9 for
// some reason, even though the devices use it.
typedef enum tagWMDM_FORMATCODE{
WMDM_FORMATCODE_NOTUSED = 0x0000,
WMDM_FORMATCODE_ALLIMAGES = 0xFFFFFFFF,
WMDM_FORMATCODE_UNDEFINED = 0x3000,
WMDM_FORMATCODE_ASSOCIATION = 0x3001,
WMDM_FORMATCODE_SCRIPT = 0x3002,
WMDM_FORMATCODE_EXECUTABLE = 0x3003,
WMDM_FORMATCODE_TEXT = 0x3004,
WMDM_FORMATCODE_HTML = 0x3005,
WMDM_FORMATCODE_DPOF = 0x3006,
WMDM_FORMATCODE_AIFF = 0x3007,
WMDM_FORMATCODE_WAVE = 0x3008,
WMDM_FORMATCODE_MP3 = 0x3009,
WMDM_FORMATCODE_AVI = 0x300A,
WMDM_FORMATCODE_MPEG = 0x300B,
WMDM_FORMATCODE_ASF = 0x300C,
WMDM_FORMATCODE_RESERVED_FIRST = 0x300D,
WMDM_FORMATCODE_RESERVED_LAST = 0x37FF,
WMDM_FORMATCODE_IMAGE_UNDEFINED = 0x3800,
WMDM_FORMATCODE_IMAGE_EXIF = 0x3801,
WMDM_FORMATCODE_IMAGE_TIFFEP = 0x3802,
WMDM_FORMATCODE_IMAGE_FLASHPIX = 0x3803,
WMDM_FORMATCODE_IMAGE_BMP = 0x3804,
WMDM_FORMATCODE_IMAGE_CIFF = 0x3805,
WMDM_FORMATCODE_IMAGE_GIF = 0x3807,
WMDM_FORMATCODE_IMAGE_JFIF = 0x3808,
WMDM_FORMATCODE_IMAGE_PCD = 0x3809,
WMDM_FORMATCODE_IMAGE_PICT = 0x380A,
WMDM_FORMATCODE_IMAGE_PNG = 0x380B,
WMDM_FORMATCODE_IMAGE_TIFF = 0x380D,
WMDM_FORMATCODE_IMAGE_TIFFIT = 0x380E,
WMDM_FORMATCODE_IMAGE_JP2 = 0x380F,
WMDM_FORMATCODE_IMAGE_JPX = 0x3810,
WMDM_FORMATCODE_IMAGE_RESERVED_FIRST = 0x3811,
WMDM_FORMATCODE_IMAGE_RESERVED_LAST = 0x3FFF,
WMDM_FORMATCODE_UNDEFINEDFIRMWARE = 0xB802,
WMDM_FORMATCODE_WINDOWSIMAGEFORMAT = 0xB881,
WMDM_FORMATCODE_UNDEFINEDAUDIO = 0xB900,
WMDM_FORMATCODE_WMA = 0xB901,
WMDM_FORMATCODE_OGG = 0xB902,
WMDM_FORMATCODE_AAC = 0xB903,
WMDM_FORMATCODE_AUDIBLE = 0xB904,
WMDM_FORMATCODE_FLAC = 0xB906,
WMDM_FORMATCODE_UNDEFINEDVIDEO = 0xB980,
WMDM_FORMATCODE_WMV = 0xB981,
WMDM_FORMATCODE_MP4 = 0xB982,
WMDM_FORMATCODE_MP2 = 0xB983,
WMDM_FORMATCODE_UNDEFINEDCOLLECTION = 0xBA00,
WMDM_FORMATCODE_ABSTRACTMULTIMEDIAALBUM = 0xBA01,
WMDM_FORMATCODE_ABSTRACTIMAGEALBUM = 0xBA02,
WMDM_FORMATCODE_ABSTRACTAUDIOALBUM = 0xBA03,
WMDM_FORMATCODE_ABSTRACTVIDEOALBUM = 0xBA04,
WMDM_FORMATCODE_ABSTRACTAUDIOVIDEOPLAYLIST = 0xBA05,
WMDM_FORMATCODE_ABSTRACTCONTACTGROUP = 0xBA06,
WMDM_FORMATCODE_ABSTRACTMESSAGEFOLDER = 0xBA07,
WMDM_FORMATCODE_ABSTRACTCHAPTEREDPRODUCTION = 0xBA08,
WMDM_FORMATCODE_WPLPLAYLIST = 0xBA10,
WMDM_FORMATCODE_M3UPLAYLIST = 0xBA11,
WMDM_FORMATCODE_MPLPLAYLIST = 0xBA12,
WMDM_FORMATCODE_ASXPLAYLIST = 0xBA13,
WMDM_FORMATCODE_PLSPLAYLIST = 0xBA14,
WMDM_FORMATCODE_UNDEFINEDDOCUMENT = 0xBA80,
WMDM_FORMATCODE_ABSTRACTDOCUMENT = 0xBA81,
WMDM_FORMATCODE_XMLDOCUMENT = 0xBA82,
WMDM_FORMATCODE_MICROSOFTWORDDOCUMENT= 0xBA83,
WMDM_FORMATCODE_MHTCOMPILEDHTMLDOCUMENT = 0xBA84,
WMDM_FORMATCODE_MICROSOFTEXCELSPREADSHEET = 0xBA85,
WMDM_FORMATCODE_MICROSOFTPOWERPOINTDOCUMENT = 0xBA86,
WMDM_FORMATCODE_UNDEFINEDMESSAGE = 0xBB00,
WMDM_FORMATCODE_ABSTRACTMESSAGE = 0xBB01,
WMDM_FORMATCODE_UNDEFINEDCONTACT = 0xBB80,
WMDM_FORMATCODE_ABSTRACTCONTACT = 0xBB81,
WMDM_FORMATCODE_VCARD2 = 0xBB82,
WMDM_FORMATCODE_VCARD3 = 0xBB83,
WMDM_FORMATCODE_UNDEFINEDCALENDARITEM = 0xBE00,
WMDM_FORMATCODE_ABSTRACTCALENDARITEM = 0xBE01,
WMDM_FORMATCODE_VCALENDAR1 = 0xBE02,
WMDM_FORMATCODE_VCALENDAR2 = 0xBE03,
WMDM_FORMATCODE_UNDEFINEDWINDOWSEXECUTABLE = 0xBE80,
WMDM_FORMATCODE_MEDIA_CAST = 0xBE81,
WMDM_FORMATCODE_SECTION = 0xBE82
} WMDM_FORMATCODE;
WmdmLoader::WmdmLoader(TaskManager* task_manager, LibraryBackend* backend,
boost::shared_ptr<ConnectedDevice> device)
: QObject(NULL),
device_(device),
task_manager_(task_manager),
backend_(backend)
{
original_thread_ = thread();
}
WmdmLoader::~WmdmLoader() {
}
void WmdmLoader::LoadDatabase() {
int task_id = task_manager_->StartTask(tr("Loading Windows Media device"));
emit TaskStarted(task_id);
boost::scoped_ptr<WmdmThread> thread(new WmdmThread);
// Get the device's canonical name
boost::shared_ptr<WmdmDevice> connected_device =
boost::static_pointer_cast<WmdmDevice>(device_);
WmdmLister* lister = static_cast<WmdmLister*>(connected_device->lister());
QString canonical_name = lister->DeviceCanonicalName(connected_device->unique_id());
// Find the device
boost::scoped_array<wchar_t> name(new wchar_t[canonical_name.length() + 1]);
canonical_name.toWCharArray(name.get());
name[canonical_name.length()] = '\0';
IWMDMDevice* device = NULL;
if (thread->manager()->GetDeviceFromCanonicalName(name.get(), &device)) {
qWarning() << "Error in GetDeviceFromCanonicalName for" << canonical_name;
return;
}
// Get the list of storages from the device
IWMDMEnumStorage* storage_it = NULL;
device->EnumStorage(&storage_it);
ULONG storage_fetched = 0;
IWMDMStorage* storage = NULL;
while (storage_it->Next(1, &storage, &storage_fetched) == S_OK) {
RecursiveExploreStorage(storage);
storage->Release();
}
storage_it->Release();
device->Release();
thread.reset();
// Need to remove all the existing songs in the database first
backend_->DeleteSongs(backend_->FindSongsInDirectory(1));
// Add the songs we've just loaded
backend_->AddOrUpdateSongs(songs_);
task_manager_->SetTaskFinished(task_id);
emit LoadFinished();
}
void WmdmLoader::RecursiveExploreStorage(IWMDMStorage* parent) {
IWMDMEnumStorage* child_it = NULL;
parent->EnumStorage(&child_it);
IWMDMStorage* child = NULL;
ULONG num_retreived = 0;
while (child_it->Next(1, &child, &num_retreived) == S_OK && num_retreived == 1) {
const int kMaxLen = 255;
wchar_t name[kMaxLen];
child->GetName(name, kMaxLen);
DWORD attributes = 0;
_WAVEFORMATEX audio_format;
child->GetAttributes(&attributes, &audio_format);
if (attributes & WMDM_FILE_ATTR_FILE) {
LoadFile(child);
} else if (attributes & WMDM_FILE_ATTR_FOLDER) {
RecursiveExploreStorage(child);
}
child->Release();
}
child_it->Release();
}
void WmdmLoader::LoadFile(IWMDMStorage* file) {
// Convert to a IWMDMStorage3 so we can get metadata
IWMDMStorage3* storage3 = NULL;
if (file->QueryInterface(IID_IWMDMStorage3, (void**) &storage3))
return;
// Get the metadata interface
IWMDMMetaData* metadata = NULL;
if (storage3->GetMetadata(&metadata)) {
storage3->Release();
return;
}
storage3->Release();
// Store the metadata in here
Song song;
bool non_consumable = false;
int format = 0;
// How much metadata is there?
uint count = 0;
metadata->GetItemCount(&count);
for (int i=0 ; i<count ; ++i) {
// Get this metadata item
wchar_t* name = NULL;
WMDM_TAG_DATATYPE type;
BYTE* value = NULL;
uint length = 0;
metadata->QueryByIndex(i, &name, &type, &value, &length);
QVariant item_value = ReadValue(type, value, length);
// Store it in the song if it's something we recognise
if (wcscmp(name, g_wszWMDMTitle) == 0)
song.set_title(item_value.toString());
else if (wcscmp(name, g_wszWMDMAuthor) == 0)
song.set_artist(item_value.toString());
else if (wcscmp(name, g_wszWMDMDescription) == 0)
song.set_comment(item_value.toString());
else if (wcscmp(name, g_wszWMDMAlbumTitle) == 0)
song.set_album(item_value.toString());
else if (wcscmp(name, g_wszWMDMTrack) == 0)
song.set_track(item_value.toInt());
else if (wcscmp(name, g_wszWMDMGenre) == 0)
song.set_genre(item_value.toString());
else if (wcscmp(name, g_wszWMDMYear) == 0)
song.set_year(item_value.toInt());
else if (wcscmp(name, g_wszWMDMComposer) == 0)
song.set_composer(item_value.toString());
else if (wcscmp(name, g_wszWMDMBitrate) == 0)
song.set_bitrate(item_value.toInt());
else if (wcscmp(name, g_wszWMDMFileName) == 0)
song.set_filename(item_value.toString());
else if (wcscmp(name, g_wszWMDMDuration) == 0)
song.set_length(item_value.toULongLong() / 10000000ll);
else if (wcscmp(name, L"WMDM/FileSize") == 0)
song.set_filesize(item_value.toULongLong());
else if (wcscmp(name, L"WMDM/NonConsumable") == 0)
non_consumable = item_value.toBool();
else if (wcscmp(name, L"WMDM/FormatCode") == 0)
format = item_value.toInt();
CoTaskMemFree(name);
CoTaskMemFree(value);
}
metadata->Release();
// Decide if this is music or not
if (count == 0 || non_consumable)
return;
switch (format) {
case WMDM_FORMATCODE_AIFF:
song.set_filetype(Song::Type_Aiff);
break;
case WMDM_FORMATCODE_WAVE:
song.set_filetype(Song::Type_Wav);
break;
case WMDM_FORMATCODE_MP2:
case WMDM_FORMATCODE_MP3:
case WMDM_FORMATCODE_MPEG:
song.set_filetype(Song::Type_Mpeg);
break;
case WMDM_FORMATCODE_WMA:
case WMDM_FORMATCODE_ASF:
song.set_filetype(Song::Type_Asf);
break;
case WMDM_FORMATCODE_OGG:
song.set_filetype(Song::Type_OggVorbis);
break;
case WMDM_FORMATCODE_AAC:
case WMDM_FORMATCODE_MP4:
song.set_filetype(Song::Type_Mp4);
break;
case WMDM_FORMATCODE_FLAC:
song.set_filetype(Song::Type_Flac);
break;
case WMDM_FORMATCODE_AUDIBLE:
case WMDM_FORMATCODE_UNDEFINEDAUDIO:
song.set_filetype(Song::Type_Unknown);
break;
default:
return; // It's not music
}
song.set_directory_id(1);
song.set_valid(true);
song.set_mtime(0);
song.set_ctime(0);
songs_ << song;
}
QVariant WmdmLoader::ReadValue(int type, uchar* data, uint length) {
switch (type) {
case WMDM_TYPE_DWORD:
return QVariant::fromValue(uint(*reinterpret_cast<DWORD*>(data)));
case WMDM_TYPE_WORD:
return QVariant::fromValue(uint(*reinterpret_cast<WORD*>(data)));
case WMDM_TYPE_QWORD:
return QVariant::fromValue(qulonglong(*reinterpret_cast<quint64*>(data)));
case WMDM_TYPE_STRING:
return QString::fromWCharArray(reinterpret_cast<wchar_t*>(data));
case WMDM_TYPE_BINARY:
return QByteArray(reinterpret_cast<char*>(data), length);
case WMDM_TYPE_BOOL:
return bool(*reinterpret_cast<int*>(data));
case WMDM_TYPE_GUID:
return QUuid(*reinterpret_cast<GUID*>(data)).toString();
}
return QVariant();
}

64
src/devices/wmdmloader.h Normal file
View File

@ -0,0 +1,64 @@
/* This file is part of Clementine.
Clementine 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.
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WMDMLOADER_H
#define WMDMLOADER_H
#include <QObject>
#include <boost/shared_ptr.hpp>
#include "core/song.h"
class ConnectedDevice;
class LibraryBackend;
class TaskManager;
struct IWMDMStorage;
class WmdmLoader : public QObject {
Q_OBJECT
public:
WmdmLoader(TaskManager* task_manager, LibraryBackend* backend,
boost::shared_ptr<ConnectedDevice> device);
~WmdmLoader();
public slots:
void LoadDatabase();
signals:
void Error(const QString& message);
void TaskStarted(int task_id);
void LoadFinished();
private:
void RecursiveExploreStorage(IWMDMStorage* parent);
void LoadFile(IWMDMStorage* file);
static QVariant ReadValue(int type, uchar* data, uint length);
private:
boost::shared_ptr<ConnectedDevice> device_;
QThread* original_thread_;
TaskManager* task_manager_;
LibraryBackend* backend_;
SongList songs_;
};
#endif // WMDMLOADER_H

View File

@ -0,0 +1,70 @@
/* This file is part of Clementine.
Clementine 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.
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "wmdmthread.h"
#include <mswmdm.h>
#include <QtDebug>
BYTE abPVK[] = {0x00};
BYTE abCert[] = {0x00};
WmdmThread::WmdmThread()
: device_manager_(NULL)
{
// Initialise COM
CoInitialize(0);
// Authenticate with WMDM
IComponentAuthenticate* auth;
if (CoCreateInstance(CLSID_MediaDevMgr, NULL, CLSCTX_ALL,
IID_IComponentAuthenticate, (void**) &auth)) {
qWarning() << "Error creating the IComponentAuthenticate interface";
return;
}
sac_ = CSecureChannelClient_New();
if (CSecureChannelClient_SetCertificate(
sac_, SAC_CERT_V1, abCert, sizeof(abCert), abPVK, sizeof(abPVK))) {
qWarning() << "Error setting SAC certificate";
return;
}
CSecureChannelClient_SetInterface(sac_, auth);
if (CSecureChannelClient_Authenticate(sac_, SAC_PROTOCOL_V1)) {
qWarning() << "Error authenticating with SAC";
return;
}
// Create the device manager
if (auth->QueryInterface(IID_IWMDeviceManager2, (void**)&device_manager_)) {
qWarning() << "Error creating WMDM device manager";
return;
}
}
WmdmThread::~WmdmThread() {
// Release the device manager
device_manager_->Release();
// SAC
CSecureChannelClient_Free(sac_);
// Uninitialise COM
CoUninitialize();
}

40
src/devices/wmdmthread.h Normal file
View File

@ -0,0 +1,40 @@
/* This file is part of Clementine.
Clementine 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.
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WMDMTHREAD_H
#define WMDMTHREAD_H
#include <QtGlobal>
#include <sac_shim.h>
struct IWMDeviceManager2;
class WmdmThread {
public:
WmdmThread();
~WmdmThread();
IWMDeviceManager2* manager() const { return device_manager_; }
private:
Q_DISABLE_COPY(WmdmThread);
IWMDeviceManager2* device_manager_;
SacHandle sac_;
};
#endif // WMDMTHREAD_H

View File

@ -967,6 +967,9 @@ msgstr ""
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr ""

View File

@ -967,6 +967,9 @@ msgstr ""
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr ""

View File

@ -988,6 +988,9 @@ msgstr "Carregant la radio de Last.fm"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr "Carregant la base de dades de l'iPod"

View File

@ -971,6 +971,9 @@ msgstr "Načítám rádio Last.fm"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr ""

View File

@ -972,6 +972,9 @@ msgstr "Indlæser Last.fm-radio"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr ""

View File

@ -987,6 +987,9 @@ msgstr "Last.fm Radio wird geladen"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr "iPod-Datenbank wird geladen"

View File

@ -987,6 +987,9 @@ msgstr "Φόρτωμα Last.fm"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr "Φόρτωση της βάσης δεδομένων iPod"

View File

@ -971,6 +971,9 @@ msgstr "Loading Last.fm radio"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr ""

View File

@ -969,6 +969,9 @@ msgstr "Loading Last.fm radio"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr ""

View File

@ -990,6 +990,9 @@ msgstr "Cargando radio de Last.fm"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr "Cargando base de datos del iPod"

View File

@ -968,6 +968,9 @@ msgstr ""
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr ""

View File

@ -981,6 +981,9 @@ msgstr "Chargement de la radio Last.fm"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr ""

View File

@ -969,6 +969,9 @@ msgstr "Carregando a rádio da Last.fm"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr ""

View File

@ -982,6 +982,9 @@ msgstr "Last.fm rádió betöltése"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr "iPod adatbázis betöltése"

View File

@ -994,6 +994,9 @@ msgstr "Caricamento radio Last.fm"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr "Caricamento database dell'iPod"

View File

@ -969,6 +969,9 @@ msgstr ""
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr ""

View File

@ -967,6 +967,9 @@ msgstr ""
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr ""

View File

@ -970,6 +970,9 @@ msgstr "Laster inn Last.fm radio"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr ""

View File

@ -984,6 +984,9 @@ msgstr "Last.fm radio laden"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr "iPod database laden"

View File

@ -967,6 +967,9 @@ msgstr "Cargament de la ràdio Last.fm"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr ""

View File

@ -976,6 +976,9 @@ msgstr "Ładowanie radia Last.fm"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr "Wczytywanie bazy danych iPod-a"

View File

@ -982,6 +982,9 @@ msgstr "Carregando a rádio Last.fm"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr "Carregando base de dados iPod"

View File

@ -977,6 +977,9 @@ msgstr "Carregando rádio Last.fm"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr ""

View File

@ -968,6 +968,9 @@ msgstr "Se încarcă radio Last.fm"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr ""

View File

@ -979,6 +979,9 @@ msgstr "Загрузка радио Last.fm"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr "Загружается база данных iPod"

View File

@ -981,6 +981,9 @@ msgstr "Načítava sa Last.fm rádio"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr "Načítava sa iPod databáza"

View File

@ -981,6 +981,9 @@ msgstr "Nalaganje Last.fm radia"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr "Nalagam iPod podatkovno bazo"

View File

@ -972,6 +972,9 @@ msgstr "Учитавам ЛастФМ радио"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr "Учитавам Ајподову базу података"

View File

@ -976,6 +976,9 @@ msgstr "Laddar Last.fm radio"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr "Läser in iPod-databas"

View File

@ -971,6 +971,9 @@ msgstr "Last.fm radyosu yükleniyor"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr "iPod veritabanı yükleniyor"

View File

@ -957,6 +957,9 @@ msgstr ""
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr ""

View File

@ -980,6 +980,9 @@ msgstr "Завантаження радіо Last.fm"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr "Завантаження бази даних iPod"

View File

@ -967,6 +967,9 @@ msgstr ""
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr ""

View File

@ -972,6 +972,9 @@ msgstr "載入 Last.fm電台"
msgid "Loading MTP device"
msgstr ""
msgid "Loading Windows Media device"
msgstr ""
msgid "Loading iPod database"
msgstr ""