From b624be98002513ff072e273ebdcae5f45deb5f5c Mon Sep 17 00:00:00 2001 From: David Sansome Date: Sat, 24 Jul 2010 16:58:14 +0000 Subject: [PATCH] Add almost-working support for writing to ipods --- src/core/musicstorage.h | 2 ++ src/core/organise.cpp | 8 +++++ src/core/organise.h | 2 ++ src/core/song.cpp | 32 ++++++++++++++++++ src/core/song.h | 1 + src/devices/connecteddevice.cpp | 3 +- src/devices/connecteddevice.h | 1 + src/devices/gpoddevice.cpp | 59 +++++++++++++++++++++++++++++++-- src/devices/gpoddevice.h | 7 ++++ 9 files changed, 111 insertions(+), 4 deletions(-) diff --git a/src/core/musicstorage.h b/src/core/musicstorage.h index f40eeb9ca..c85bc9057 100644 --- a/src/core/musicstorage.h +++ b/src/core/musicstorage.h @@ -30,9 +30,11 @@ public: virtual QString LocalPath() const { return QString(); } + virtual void StartCopy() {} virtual bool CopyToStorage(const QString& source, const QString& destination, const Song& metadata, bool overwrite, bool remove_original) = 0; + virtual void FinishCopy() {} }; Q_DECLARE_METATYPE(MusicStorage*); diff --git a/src/core/organise.cpp b/src/core/organise.cpp index 0606fd602..69ba2aaec 100644 --- a/src/core/organise.cpp +++ b/src/core/organise.cpp @@ -35,6 +35,7 @@ Organise::Organise(TaskManager* task_manager, MusicStorage* destination, copy_(copy), overwrite_(overwrite), files_(files), + started_(false), task_id_(0), progress_(0) { @@ -56,8 +57,15 @@ void Organise::Start() { } void Organise::ProcessSomeFiles() { + if (!started_) { + destination_->StartCopy(); + started_ = true; + } + // None left? if (progress_ >= files_.count()) { + destination_->FinishCopy(); + task_manager_->SetTaskFinished(task_id_); // Move back to the original thread so deleteLater() can get called in diff --git a/src/core/organise.h b/src/core/organise.h index 2d9b78245..b00955e5e 100644 --- a/src/core/organise.h +++ b/src/core/organise.h @@ -50,6 +50,8 @@ private: const bool overwrite_; QStringList files_; + bool started_; + int task_id_; int progress_; }; diff --git a/src/core/song.cpp b/src/core/song.cpp index 3ffabe968..e722e4b1e 100644 --- a/src/core/song.cpp +++ b/src/core/song.cpp @@ -562,6 +562,38 @@ void Song::InitFromLastFM(const lastfm::Track& track) { d->filename_ = QString::fromLocal8Bit(track->ipod_path); d->basefilename_ = QFileInfo(d->filename_).fileName(); } + + static void CopyStr(const QString& str, gchar** dest_p) { + Q_ASSERT(*dest_p == NULL); + const QByteArray data = str.toUtf8(); + const int size = data.size() + 1; + + gchar* dest = new gchar[size]; + std::copy(data.constData(), data.constData() + size, dest); + *dest_p = dest; + } + + void Song::ToItdb(Itdb_Track *track) const { + CopyStr(d->title_, &track->title); + CopyStr(d->album_, &track->album); + CopyStr(d->artist_, &track->artist); + CopyStr(d->albumartist_, &track->albumartist); + CopyStr(d->composer_, &track->composer); + track->track_nr = d->track_; + track->cd_nr = d->disc_; + track->BPM = d->bpm_; + track->year = d->year_; + CopyStr(d->genre_, &track->genre); + CopyStr(d->comment_, &track->comment); + track->compilation = d->compilation_; + track->tracklen = d->length_ * 1000; + track->bitrate = d->bitrate_; + track->samplerate = d->samplerate_; + track->time_modified = d->mtime_; + track->time_added = d->ctime_; + track->size = d->filesize_; + track->type2 = d->filetype_ == Type_Mp4 ? 0 : 1; + } #endif void Song::MergeFromSimpleMetaBundle(const Engine::SimpleMetaBundle &bundle) { diff --git a/src/core/song.h b/src/core/song.h index a1b333fbf..6148f6dfb 100644 --- a/src/core/song.h +++ b/src/core/song.h @@ -128,6 +128,7 @@ class Song { #ifdef HAVE_LIBGPOD void InitFromItdb(Itdb_Track* track); + void ToItdb(Itdb_Track* track) const; #endif static QString Decode(const TagLib::String& tag, const QTextCodec* codec); diff --git a/src/devices/connecteddevice.cpp b/src/devices/connecteddevice.cpp index a76587db7..80f2fbc6f 100644 --- a/src/devices/connecteddevice.cpp +++ b/src/devices/connecteddevice.cpp @@ -23,10 +23,11 @@ #include -ConnectedDevice::ConnectedDevice(const QUrl&, DeviceLister* lister, +ConnectedDevice::ConnectedDevice(const QUrl& url, DeviceLister* lister, const QString& unique_id, DeviceManager* manager, int database_id, bool) : QObject(manager), + url_(url), lister_(lister), unique_id_(unique_id), database_id_(database_id), diff --git a/src/devices/connecteddevice.h b/src/devices/connecteddevice.h index 4ccf33ed1..eefb5e2be 100644 --- a/src/devices/connecteddevice.h +++ b/src/devices/connecteddevice.h @@ -51,6 +51,7 @@ protected: void InitBackendDirectory(const QString& mount_point, bool first_time); protected: + QUrl url_; DeviceLister* lister_; QString unique_id_; int database_id_; diff --git a/src/devices/gpoddevice.cpp b/src/devices/gpoddevice.cpp index 619d49c7b..38578339a 100644 --- a/src/devices/gpoddevice.cpp +++ b/src/devices/gpoddevice.cpp @@ -29,7 +29,8 @@ GPodDevice::GPodDevice( int database_id, bool first_time) : ConnectedDevice(url, lister, unique_id, manager, database_id, first_time), loader_thread_(new QThread(this)), - loader_(new GPodLoader(url.path(), manager->task_manager(), backend_)) + loader_(new GPodLoader(url.path(), manager->task_manager(), backend_)), + active_copy_db_(NULL) { InitBackendDirectory(url.path(), first_time); model_->Init(); @@ -44,13 +45,65 @@ GPodDevice::GPodDevice( } GPodDevice::~GPodDevice() { +} +void GPodDevice::StartCopy() { + active_copy_mutex_.lock(); + + // Load the iTunes database + GError* error = NULL; + active_copy_db_ = itdb_parse(url_.path().toLocal8Bit(), &error); + + // Check for errors + if (!active_copy_db_) { + qDebug() << "GPodDevice error:" << error->message; + emit Error(QString::fromUtf8(error->message)); + g_error_free(error); + } } bool GPodDevice::CopyToStorage( - const QString &source, const QString &destination, - const Song &metadata, bool overwrite, bool remove_original) + const QString& source, const QString&, + const Song& metadata, bool, bool remove_original) { + if (!active_copy_db_) + return false; + + // Create the track + Itdb_Track* track = itdb_track_new(); + metadata.ToItdb(track); + + // Add it to the DB and the master playlist + // The DB takes ownership of the track + itdb_track_add(active_copy_db_, track, -1); + Itdb_Playlist* mpl = itdb_playlist_mpl(active_copy_db_); + itdb_playlist_add_track(mpl, track, -1); + + // Copy the file + GError* error = NULL; + itdb_cp_track_to_ipod(track, source.toLocal8Bit().constData(), &error); + if (error) { + qDebug() << "GPodDevice error:" << error->message; + emit Error(QString::fromUtf8(error->message)); + g_error_free(error); + + // Need to remove the track from the db again + itdb_track_remove(track); + return false; + } + return true; } +void GPodDevice::FinishCopy() { + GError* error = NULL; + itdb_write(active_copy_db_, &error); + if (error) { + qDebug() << "GPodDevice error:" << error->message; + emit Error(QString::fromUtf8(error->message)); + g_error_free(error); + } + + active_copy_mutex_.unlock(); +} + diff --git a/src/devices/gpoddevice.h b/src/devices/gpoddevice.h index 0df5d0aa3..2937381cb 100644 --- a/src/devices/gpoddevice.h +++ b/src/devices/gpoddevice.h @@ -20,6 +20,8 @@ #include "connecteddevice.h" #include "core/musicstorage.h" +#include + class GPodLoader; class GPodDevice : public ConnectedDevice, public MusicStorage { @@ -36,12 +38,17 @@ public: MusicStorage* storage() { return this; } + void StartCopy(); bool CopyToStorage(const QString &source, const QString &destination, const Song &metadata, bool overwrite, bool remove_original); + void FinishCopy(); private: QThread* loader_thread_; GPodLoader* loader_; + + QMutex active_copy_mutex_; + Itdb_iTunesDB* active_copy_db_; }; #endif // GPODDEVICE_H