summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRJ Ryan <rryan@mixxx.org>2014-10-28 10:14:05 -0400
committerRJ Ryan <rryan@mixxx.org>2014-10-28 10:26:23 -0400
commitb90c5c6d794c4db518cc9ea2305069ab872332ef (patch)
tree9b633a84ad37a7ebb2e338c587085082885d1524 /src
parenta4132dee5a7b9e3a51b3424adbf273f17af877f2 (diff)
Add first pass at cover art scan for UNKNOWN tracks.
Diffstat (limited to 'src')
-rw-r--r--src/library/dao/trackdao.cpp113
-rw-r--r--src/library/dao/trackdao.h1
-rw-r--r--src/library/libraryscanner.cpp7
3 files changed, 118 insertions, 3 deletions
diff --git a/src/library/dao/trackdao.cpp b/src/library/dao/trackdao.cpp
index 48551ae939..8ebdfe463e 100644
--- a/src/library/dao/trackdao.cpp
+++ b/src/library/dao/trackdao.cpp
@@ -1,6 +1,10 @@
#include <QtDebug>
#include <QDir>
+#include <QDirIterator>
+#include <QFileInfo>
#include <QtSql>
+#include <QImage>
+#include <QRegExp>
#include "library/dao/trackdao.h"
@@ -11,6 +15,8 @@
#include "track/beats.h"
#include "track/keyfactory.h"
#include "trackinfoobject.h"
+#include "library/coverart.h"
+#include "library/coverartutils.h"
#include "library/dao/cratedao.h"
#include "library/dao/cuedao.h"
#include "library/dao/playlistdao.h"
@@ -1539,3 +1545,110 @@ bool TrackDAO::verifyRemainingTracks(volatile bool* pCancel) {
qDebug() << "verifyTracksOutside finished";
return true;
}
+
+void TrackDAO::detectCoverArtForUnknownTracks(volatile bool* pCancel) {
+ QSqlQuery query(m_database);
+ query.prepare("SELECT "
+ " library.id, " // 0
+ " track_locations.location, " // 1
+ " track_locations.directory, " // 2
+ " album " // 3
+ "FROM library "
+ "INNER JOIN track_locations "
+ "ON library.location = track_locations.id "
+ // CoverInfo::Source 0 is UNKNOWN
+ "WHERE coverart_source is NULL or coverart_source = 0 "
+ "ORDER BY track_locations.directory");
+
+ QSqlQuery updateQuery(m_database);
+ updateQuery.prepare(
+ "UPDATE library SET "
+ " coverart_type=:coverart_type,"
+ " coverart_source=:coverart_source,"
+ " coverart_hash=:coverart_hash,"
+ " coverart_location=:coverart_location "
+ "WHERE id=:track_id");
+
+ if (!query.exec()) {
+ LOG_FAILED_QUERY(query)
+ << "failed looking for tracks with unknown cover art";
+ return;
+ }
+
+ QRegExp coverArtFilenames(CoverArtUtils::supportedCoverArtExtensionsRegex(),
+ Qt::CaseInsensitive);
+ QString currentDirectory;
+ QLinkedList<QFileInfo> possibleCovers;
+ while (query.next()) {
+ if (*pCancel) {
+ return;
+ }
+
+ int trackId = query.value(0).toInt();
+ QString trackLocation = query.value(1).toString();
+ // TODO(rryan) use QFileInfo path instead? symlinks? relative?
+ QString directory = query.value(2).toString();
+ QString trackAlbum = query.value(3).toString();
+
+ qDebug() << "Searching for cover art for" << trackLocation;
+
+ QFileInfo trackInfo(trackLocation);
+ if (!trackInfo.exists()) {
+ qDebug() << trackLocation << "does not exist";
+ continue;
+ }
+
+ SecurityTokenPointer pToken = Sandbox::openSecurityToken(trackInfo, true);
+ SoundSourceProxy proxy(trackLocation, pToken);
+ Mixxx::SoundSource* pProxiedSoundSource = proxy.getProxiedSoundSource();
+ if (pProxiedSoundSource != NULL) {
+ QImage image = proxy.parseCoverArt();
+ if (!image.isNull()) {
+ updateQuery.bindValue(":coverart_type",
+ static_cast<int>(CoverInfo::METADATA));
+ updateQuery.bindValue(":coverart_source",
+ static_cast<int>(CoverInfo::GUESSED));
+ updateQuery.bindValue(":coverart_hash",
+ CoverArtUtils::calculateHash(image));
+ updateQuery.bindValue(":coverart_location", "");
+ updateQuery.bindValue(":track_id", trackId);
+ if (!updateQuery.exec()) {
+ LOG_FAILED_QUERY(updateQuery) << "failed to write metadata cover";
+ }
+ continue;
+ }
+ }
+
+ if (directory != currentDirectory) {
+ possibleCovers.clear();
+ currentDirectory = directory;
+ QDirIterator it(directory,
+ QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
+ QFile currentFile;
+ QFileInfo currentFileInfo;
+ QLinkedList<QFileInfo> possibleCovers;
+ while (it.hasNext()) {
+ it.next();
+ currentFileInfo = it.fileInfo();
+ if (currentFileInfo.isFile() &&
+ coverArtFilenames.indexIn(currentFileInfo.fileName()) != -1) {
+ possibleCovers.append(currentFileInfo);
+ }
+ }
+ }
+
+ CoverArt art = CoverArtUtils::selectCoverArtForTrack(
+ trackInfo.baseName(), trackAlbum, possibleCovers);
+
+ updateQuery.bindValue(":coverart_type",
+ static_cast<int>(art.info.type));
+ updateQuery.bindValue(":coverart_source",
+ static_cast<int>(art.info.source));
+ updateQuery.bindValue(":coverart_hash", art.info.hash);
+ updateQuery.bindValue(":coverart_location", art.info.coverLocation);
+ updateQuery.bindValue(":track_id", trackId);
+ if (!updateQuery.exec()) {
+ LOG_FAILED_QUERY(updateQuery) << "failed to write file or none cover";
+ }
+ }
+}
diff --git a/src/library/dao/trackdao.h b/src/library/dao/trackdao.h
index 0af607bf3f..a1e32bf7fb 100644
--- a/src/library/dao/trackdao.h
+++ b/src/library/dao/trackdao.h
@@ -114,6 +114,7 @@ class TrackDAO : public QObject, public virtual DAO {
void databaseTrackAdded(TrackPointer pTrack);
void databaseTracksMoved(QSet<int> tracksMovedSetOld, QSet<int> tracksMovedSetNew);
bool verifyRemainingTracks(volatile bool* pCancel);
+ void detectCoverArtForUnknownTracks(volatile bool* pCancel);
signals:
void trackDirty(int trackId);
diff --git a/src/library/libraryscanner.cpp b/src/library/libraryscanner.cpp
index 915587ed0f..777e1dc5f1 100644
--- a/src/library/libraryscanner.cpp
+++ b/src/library/libraryscanner.cpp
@@ -287,6 +287,10 @@ void LibraryScanner::run() {
m_libraryHashDao.removeDeletedDirectoryHashes();
transaction.commit();
+
+ qDebug() << "Detecting cover art for unscanned files.";
+ m_trackDao.detectCoverArtForUnknownTracks(&m_bCancelLibraryScan);
+
qDebug() << "Scan finished cleanly";
} else {
qDebug() << "Scan cancelled";
@@ -467,9 +471,6 @@ bool LibraryScanner::importFiles(const QLinkedList<QFileInfo>& files,
} else {
qDebug() << "Track ("+filePath+") could not be added";
}
- } else {
- // TODO(rryan): Potentially automatically update the cover of the
- // track.
}
}