Check if song exists on device before sending

This commit is contained in:
craig.p.drummond
2013-02-27 19:43:52 +00:00
committed by craig.p.drummond
parent 5175a836c1
commit 65b4b8476f
2 changed files with 88 additions and 66 deletions

View File

@@ -444,13 +444,16 @@ void MtpConnection::updateFiles()
while (file) {
if (folders.contains(file->parent_id)) {
Folder &folder=folderMap[file->parent_id];
if (LIBMTP_FILETYPE_FOLDER!=file->filetype) {
if (LIBMTP_FILETYPE_FOLDER==file->filetype) {
folder.folders.insert(file->item_id);
} else {
QString name=QString::fromUtf8(file->filename);
if (name.endsWith(".jpg", Qt::CaseInsensitive) || name.endsWith(".png", Qt::CaseInsensitive) || QLatin1String("albumart.pamp")==name) {
folder.covers.insert(file->item_id, Cover(name, file->filesize, file->item_id));
folder.covers.insert(file->item_id, File(name, file->filesize, file->item_id));
} else {
folder.files.insert(file->item_id, File(name, file->filesize, file->item_id));
}
}
folder.children.insert(file->item_id);
}
file=file->next;
}
@@ -610,6 +613,9 @@ void MtpConnection::parseFolder(LIBMTP_folder_t *folder)
bool isMusic=path.startsWith(QLatin1String("Music/"), Qt::CaseInsensitive);
if (isMusic) {
folderMap.insert(folder->folder_id, Folder(path, folder->folder_id, folder->parent_id, folder->storage_id));
if (folderMap.contains(folder->parent_id)) {
folderMap[folder->parent_id].folders.insert(folder->folder_id);
}
}
// Only recurse into music folder...
if (folder->child && isMusic) {
@@ -703,9 +709,9 @@ static QTemporaryFile * saveImageToTemp(const QImage &img, const QString &name)
return temp;
}
void MtpConnection::putSong(const Song &s, bool fixVa, const DeviceOptions &opts, bool copyCover)
void MtpConnection::putSong(const Song &s, bool fixVa, const DeviceOptions &opts, bool overwrite, bool copyCover)
{
bool added=false;
int status=Device::Failed;
bool fixedVa=false;
bool embedCoverImage=Device::constEmbedCover==opts.coverName;
bool copiedCover=false;
@@ -762,20 +768,34 @@ void MtpConnection::putSong(const Song &s, bool fixVa, const DeviceOptions &opts
destName=dirs.takeLast();
meta->parent_id=folderId=checkFolderStructure(dirs, store);
}
meta->title=createString(song.title);
meta->artist=createString(song.artist);
meta->composer=createString(QString());
meta->genre=createString(song.genre);
meta->album=createString(song.album);
meta->date=createString(QString().sprintf("%4d0101T0000.0", song.year));
meta->filename=createString(destName);
meta->tracknumber=song.track;
meta->duration=song.time*1000;
meta->rating=0;
meta->usecount=0;
meta->filetype=mtpFileType(song.file);
meta->next=0;
added=0==LIBMTP_Send_Track_From_File(device, fileName.toUtf8(), meta, &progressMonitor, this);
Folder &folder=folderMap[folderId];
QMap<uint32_t, File>::ConstIterator it=folder.files.constBegin();
QMap<uint32_t, File>::ConstIterator end=folder.files.constEnd();
for (; it!=end; ++it) {
if ((*it).name==destName) {
if (!overwrite || 0!=LIBMTP_Delete_Object(device, (*it).id)) {
status=Device::SongExists;
}
break;
}
}
if (status!=Device::SongExists) {
meta->title=createString(song.title);
meta->artist=createString(song.artist);
meta->composer=createString(QString());
meta->genre=createString(song.genre);
meta->album=createString(song.album);
meta->date=createString(QString().sprintf("%4d0101T0000.0", song.year));
meta->filename=createString(destName);
meta->tracknumber=song.track;
meta->duration=song.time*1000;
meta->rating=0;
meta->usecount=0;
meta->filetype=mtpFileType(song.file);
meta->next=0;
status=0==LIBMTP_Send_Track_From_File(device, fileName.toUtf8(), meta, &progressMonitor, this) ? Device::Ok : Device::Failed;
}
if (temp) {
// Delete the temp file...
temp->remove();
@@ -783,13 +803,13 @@ void MtpConnection::putSong(const Song &s, bool fixVa, const DeviceOptions &opts
}
}
if (added) {
if (Device::Ok==status) {
Folder &folder=folderMap[folderId];
// LibMTP seems to reset parent_id to 0 - but we NEED the correct value for encodePath
meta->parent_id=folderId;
if (copyCover) {
QMap<uint32_t, Cover>::ConstIterator it=folder.covers.constBegin();
QMap<uint32_t, Cover>::ConstIterator end=folder.covers.constEnd();
QMap<uint32_t, File>::ConstIterator it=folder.covers.constBegin();
QMap<uint32_t, File>::ConstIterator end=folder.covers.constEnd();
for (; it!=end; ++it) {
if (it.value().name==opts.coverName) {
@@ -831,8 +851,7 @@ void MtpConnection::putSong(const Song &s, bool fixVa, const DeviceOptions &opts
meta->filetype=mtpFileType(opts.coverName);
if (0==LIBMTP_Send_File_From_File(device, srcFile.toUtf8(), fileMeta, 0, 0)) {
folder.children.insert(fileMeta->item_id);
folder.covers.insert(fileMeta->item_id, Cover(opts.coverName, statBuf.st_size, fileMeta->item_id));
folder.covers.insert(fileMeta->item_id, File(opts.coverName, statBuf.st_size, fileMeta->item_id));
copiedCover=true;
}
LIBMTP_destroy_file_t(fileMeta);
@@ -842,9 +861,9 @@ void MtpConnection::putSong(const Song &s, bool fixVa, const DeviceOptions &opts
delete temp;
}
}
folder.children.insert(meta->item_id);
folder.files.insert(meta->item_id, File(destName, meta->filesize, meta->item_id));
}
emit putSongStatus(added, meta ? meta->item_id : 0,
emit putSongStatus(status,
meta ? encodePath(meta, destName, storage.count()>1 ? store.description : QString()) : QString(),
fixedVa, copiedCover);
if (meta) {
@@ -852,14 +871,14 @@ void MtpConnection::putSong(const Song &s, bool fixVa, const DeviceOptions &opts
}
}
MtpConnection::Cover MtpConnection::getCoverDetils(const Song &s)
MtpConnection::File MtpConnection::getCoverDetils(const Song &s)
{
MtpConnection::Cover cover;
File cover;
Path path=decodePath(s.file);
if (path.ok() && folderMap.contains(path.parent) && !folderMap[path.parent].covers.isEmpty()) {
QMap<uint32_t, Cover> &covers=folderMap[path.parent].covers;
QMap<uint32_t, Cover>::ConstIterator it=covers.constBegin();
QMap<uint32_t, Cover>::ConstIterator end=covers.constEnd();
QMap<uint32_t, File> &covers=folderMap[path.parent].covers;
QMap<uint32_t, File>::ConstIterator it=covers.constBegin();
QMap<uint32_t, File>::ConstIterator end=covers.constEnd();
for (; it!=end; ++it) {
if (it.value().size>cover.size) {
@@ -880,7 +899,7 @@ void MtpConnection::getSong(const Song &song, const QString &dest, bool fixVa, b
QString destDir=Utils::getDir(dest);
if (QDir(destDir).entryList(QStringList() << QLatin1String("*.jpg") << QLatin1String("*.png"), QDir::Files|QDir::Readable).isEmpty()) {
Cover cover=getCoverDetils(song);
File cover=getCoverDetils(song);
if (0!=cover.id) {
QString mpdCover=MPDConnection::self()->getDetails().coverName;
@@ -909,7 +928,7 @@ void MtpConnection::delSong(const Song &song)
Path path=decodePath(song.file);
bool deletedSong=device && path.ok() && 0==LIBMTP_Delete_Object(device, path.id);
if (deletedSong) {
folderMap[path.parent].children.remove(path.id);
folderMap[path.parent].files.remove(path.id);
}
emit delSongStatus(deletedSong);
}
@@ -917,21 +936,20 @@ void MtpConnection::delSong(const Song &song)
bool MtpConnection::removeFolder(uint32_t folderId)
{
QMap<uint32_t, Folder>::iterator folder=folderMap.find(folderId);
if (folderMap.end()!=folder) {
if (!(*folder).children.isEmpty()) {
// If we only have covers left, then remove them!
if ((*folder).children.count()==(*folder).covers.count()) {
QList<uint32_t> toRemove=(*folder).covers.keys();
foreach (uint32_t cover, toRemove) {
if (0==LIBMTP_Delete_Object(device, cover)) {
(*folder).covers.remove(cover);
(*folder).children.remove(cover);
}
}
if (folderMap.end()!=folder && (*folder).folders.isEmpty() && (*folder).files.isEmpty()) {
// Delete any cover files...
QList<uint32_t> toRemove=(*folder).covers.keys();
foreach (uint32_t cover, toRemove) {
if (0==LIBMTP_Delete_Object(device, cover)) {
(*folder).covers.remove(cover);
}
}
if ((*folder).children.isEmpty() && 0==LIBMTP_Delete_Object(device, folderId)) {
// Delete folder, if it is now empty...
if ((*folder).covers.isEmpty() && 0==LIBMTP_Delete_Object(device, folderId)) {
if (folderMap.contains((*folder).parentId)) {
folderMap[(*folder).parentId].folders.remove(folderId);
}
folderMap.remove(folderId);
return true;
}
@@ -968,7 +986,7 @@ void MtpConnection::cleanDirs(const QSet<QString> &dirs)
void MtpConnection::getCover(const Song &song)
{
Cover c=getCoverDetils(song);
File c=getCoverDetils(song);
if (0!=c.id) {
QByteArray data;
@@ -1032,8 +1050,8 @@ MtpDevice::MtpDevice(DevicesModel *m, Solid::Device &dev)
connect(this, SIGNAL(updateLibrary()), connection, SLOT(updateLibrary()));
connect(connection, SIGNAL(libraryUpdated()), this, SLOT(libraryUpdated()));
connect(connection, SIGNAL(progress(int)), this, SLOT(emitProgress(int)));
connect(this, SIGNAL(putSong(const Song &, bool, const DeviceOptions &, bool)), connection, SLOT(putSong(const Song &, bool, const DeviceOptions &, bool)));
connect(connection, SIGNAL(putSongStatus(bool, int, const QString &, bool, bool)), this, SLOT(putSongStatus(bool, int, const QString &, bool, bool)));
connect(this, SIGNAL(putSong(const Song &, bool, const DeviceOptions &, bool, bool)), connection, SLOT(putSong(const Song &, bool, const DeviceOptions &, bool, bool)));
connect(connection, SIGNAL(putSongStatus(int, const QString &, bool, bool)), this, SLOT(putSongStatus(int, const QString &, bool, bool)));
connect(this, SIGNAL(getSong(const Song &, const QString &, bool, bool)), connection, SLOT(getSong(const Song &, const QString &, bool, bool)));
connect(connection, SIGNAL(getSongStatus(bool, bool)), this, SLOT(getSongStatus(bool, bool)));
connect(this, SIGNAL(delSong(const Song &)), connection, SLOT(delSong(const Song &)));
@@ -1160,8 +1178,9 @@ void MtpDevice::addSong(const Song &s, bool overwrite, bool copyCover)
QFile::remove(destFile);
}
transcoding=true;
needToCopyCover=copyCover;
TranscodingJob *job=new TranscodingJob(encoder, opts.transcoderValue, s.file, destFile);
job->setProperty("overwrite", overwrite);
job->setProperty("copyCover", copyCover);
connect(job, SIGNAL(result(int)), SLOT(transcodeSongResult(int)));
connect(job, SIGNAL(percent(int)), SLOT(transcodePercent(int)));
job->start();
@@ -1170,7 +1189,7 @@ void MtpDevice::addSong(const Song &s, bool overwrite, bool copyCover)
}
}
transcoding=false;
emit putSong(currentSong, needToFixVa, opts, copyCover);
emit putSong(currentSong, needToFixVa, opts, overwrite, copyCover);
}
void MtpDevice::copySongTo(const Song &s, const QString &baseDir, const QString &musicPath, bool overwrite, bool copyCover)
@@ -1249,16 +1268,15 @@ void MtpDevice::requestCover(const Song &song)
}
}
void MtpDevice::putSongStatus(bool ok, int id, const QString &file, bool fixedVa, bool copiedCover)
void MtpDevice::putSongStatus(int status, const QString &file, bool fixedVa, bool copiedCover)
{
deleteTemp();
if (jobAbortRequested) {
return;
}
if (!ok) {
emit actionStatus(Failed);
if (Ok!=status) {
emit actionStatus(status);
} else {
currentSong.id=id;
currentSong.file=file;
if (needToFixVa && fixedVa) {
currentSong.fixVariousArtists();
@@ -1275,7 +1293,11 @@ void MtpDevice::putSongStatus(bool ok, int id, const QString &file, bool fixedVa
void MtpDevice::transcodeSongResult(int status)
{
FileJob::finished(sender());
TranscodingJob *job=qobject_cast<TranscodingJob *>(sender());
if (!job) {
return;
}
FileJob::finished(job);
if (jobAbortRequested) {
deleteTemp();
return;
@@ -1283,7 +1305,7 @@ void MtpDevice::transcodeSongResult(int status)
if (Ok!=status) {
emit actionStatus(status);
} else {
emit putSong(currentSong, needToFixVa, opts, needToCopyCover);
emit putSong(currentSong, needToFixVa, opts, job->property("overwrite").toBool(), job->property("copyCover").toBool());
}
}

View File

@@ -42,8 +42,8 @@ class MtpConnection : public QObject
{
Q_OBJECT
public:
struct Cover {
Cover(const QString &n=QString(), uint64_t s=0, uint32_t i=0) : name(n), size(s), id(i) { }
struct File {
File(const QString &n=QString(), uint64_t s=0, uint32_t i=0) : name(n), size(s), id(i) { }
QString name;
uint64_t size;
uint32_t id;
@@ -60,8 +60,9 @@ public:
uint32_t id;
uint32_t parentId;
uint32_t storageId;
QSet<uint32_t> children;
QMap<uint32_t, Cover> covers;
QSet<uint32_t> folders;
QMap<uint32_t, File> files;
QMap<uint32_t, File> covers;
};
struct Storage : public DeviceStorage {
@@ -87,7 +88,7 @@ public Q_SLOTS:
void connectToDevice();
void disconnectFromDevice(bool showStatus=true);
void updateLibrary();
void putSong(const Song &song, bool fixVa, const DeviceOptions &opts, bool copyCover);
void putSong(const Song &song, bool fixVa, const DeviceOptions &opts, bool overwrite, bool copyCover);
void getSong(const Song &song, const QString &dest, bool fixVa, bool copyCover);
void delSong(const Song &song);
void cleanDirs(const QSet<QString> &dirs);
@@ -95,7 +96,7 @@ public Q_SLOTS:
Q_SIGNALS:
void statusMessage(const QString &message);
void putSongStatus(bool, int, const QString &, bool, bool);
void putSongStatus(int, const QString &, bool, bool);
void getSongStatus(bool ok, bool copiedCover);
void delSongStatus(bool);
void cleanDirsStatus(bool ok);
@@ -106,7 +107,7 @@ Q_SIGNALS:
void cover(const Song &s, const QImage &img);
private:
Cover getCoverDetils(const Song &s);
File getCoverDetils(const Song &s);
bool removeFolder(uint32_t folderId);
void updateFolders();
void updateFiles();
@@ -160,7 +161,7 @@ public:
Q_SIGNALS:
// These are for talking to connection thread...
void updateLibrary();
void putSong(const Song &song, bool fixVa, const DeviceOptions &opts, bool copyCover);
void putSong(const Song &song, bool fixVa, const DeviceOptions &opts, bool overwrite, bool copyCover);
void getSong(const Song &song, const QString &dest, bool fixVa, bool copyCover);
void delSong(const Song &song);
void cleanMusicDirs(const QSet<QString> &dirs);
@@ -171,7 +172,7 @@ private Q_SLOTS:
void deviceDetails(const QString &s);
void libraryUpdated();
void rescan(bool full=true);
void putSongStatus(bool ok, int id, const QString &file, bool fixedVa, bool copiedCover);
void putSongStatus(int status, const QString &file, bool fixedVa, bool copiedCover);
void transcodeSongResult(int status);
void transcodePercent(int percent);
void emitProgress(int);
@@ -190,7 +191,6 @@ private:
MtpConnection *connection;
QTemporaryFile *tempFile;
Song currentSong;
bool needToCopyCover;
bool mtpUpdating;
QString serial;
unsigned int busNum;